Transpile WordMath

25

Kita semua telah melihat "hax matematika" daring yang terlihat seperti ini:

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

Dan, secara ajaib, semua orang berakhir dengan angka 8!


Bahasa

Mari kita mendefinisikan bahasa pemrograman yang menggunakan sintaks teks di atas, yang disebut "WordMath". Script WordMath ikuti templat ini:

Think of a number, <commandlist>.

Yang pada dasarnya berarti: Ambil nomor (sebagai input dari STDIN) sebagai akumulator awal, lakukan semua perintah di atasnya, dan hasilkan hasilnya.

Perintah dipisahkan oleh pembatas ,(koma + spasi). Perintah yang valid adalah (catatan yang #mewakili integer non-negatif :) :

  • add #/ subtract #- Tambahkan / kurangi nilai dari akumulator.
  • divide by #/ multiply by #- floordiv / kalikan akumulator dengan nilai yang diberikan.
  • subtract from #- Mirip dengan subtract, tetapi acc = # - accbukanacc = acc - #
  • repeat- lakukan perintah terakhir lagi. Ini bukan perintah pertama, tetapi Anda harus mendukung berulang berulang kali.

Tantangan

Tugas Anda adalah untuk membuat program atau fungsi yang mengambil script WordMath berlaku sebagai masukan dan transpiles menjadi program penuh valid - dalam bahasa yang sama kode Anda di.

Misalnya, jika kode saya ada di Python 2 dan skripnya adalah:

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

Program yang dihasilkan dapat:

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

Atau sebagai alternatif:

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

Selama itu adalah program lengkap yang mengambil input dari STDINdan dicetak ke STDOUT, atau setara bahasa terdekat.


Aturan

  • Program asli Anda dapat mengasumsikan bahwa input selalu berupa skrip WordMath yang valid.
  • Program yang diubah-ubah tidak harus menangani kesalahan matematika seperti pembagian dengan 0.
  • Program yang diubah-ubah dapat mengasumsikan bahwa input mewakili integer bertanda tangan yang valid, dalam rentang integer standar bahasa Anda.
  • Ini adalah , sehingga solusi terpendek (dalam byte) menang.
  • Hanya hitungan byte dari program asli Anda yang penting - kode yang dihasilkan dapat sepanjang yang Anda inginkan!

Contoh Skrip

Contoh 1:

Think of a number. 

Ambil input, jangan lakukan apa-apa, tampilkan: Program kucing WordMath.

Contoh 2:

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

Ingat bahwa "membagi" adalah pembagian lantai, jadi untuk program ini 6 -> 8, dan 29 -> 4.

Contoh 3:

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

Program kucing diperpanjang!

Contoh 4:

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

Mengambil angka dan mengurangi 3.

FlipTack
sumber
Apakah kita harus mendukung pengulangan yang berurutan?
darrylyeo
1
Bisakah kita menggunakan float ketika itu jenis bahasa default / jika tidak mendukung bilangan bulat?
Rainer P.
@RainerP. hanya jika bahasa tidak mendukung pembagian bilangan bulat / integer
FlipTack
1
Apa hasil yang diharapkan -5/3? Apakah kita berputar menuju 0atau menuju infinity negatif?
Martin Ender
1
@ MartinEnder Saya akan mengatakan bulat menuju infinity negatif karena itu adalah pembagian lantai , tetapi jika bahasa Anda menerapkan pembagian bilangan bulat ke 0 itu juga baik.
FlipTack

Jawaban:

6

05AB1E , 59 56 54 52 byte

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

Cobalah online!

Otak saya sakit sekali setelah itu ... Outputnya dalam kode 05AB1E sebagai berikut:

  • Think of a Number dihapus, karena input implisit.
  • Subtract From #bulu ke #s-(pertukaran adan bdan melakukan operasi).
  • Subtract #dikonversi ke #-.
  • Add #dikonversi ke #+.
  • Multiply by #dikonversi ke #*.
  • Divide by #dikonversi ke #/.
  • Repeat meraih apa pun yang terakhir disimpan dalam register dan menyatukannya.

Dijelaskan:

„, ¡                                                 # 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.

Contoh:

Memasukkan:

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

Keluaran:

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

Coba solusi dengan input 10:

Cobalah online!

Lihat di google:

Berikut tautan ke persamaan yang sama yang diketikkan ke google.

Guci Gurita Ajaib
sumber
13

C Preprocessor, 362 Bytes

SAYA HAMPIR menjalankan ini di HANYA preprocessor C, tetapi perintah repeat ternyata terlalu sulit untuk diimplementasikan. Jadi alih-alih saya menggunakan preprocessor untuk mengubah input menjadi array yang kemudian ditafsirkan oleh beberapa kode tambahan.

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",_);}

Input harus disediakan di "input.wm" atau baru saja dibuang di sumber di baris itu. Saya memasukkan byte-nya ke dalam hitungan saya karena saya pikir itu sedikit aneh dan sedikit bertentangan dengan aturan tantangan, jadi itu hanya cocok.

Bagaimanapun, setelah Anda membuang sumber WordMath Anda ke input.wm di mana kompiler dapat menemukannya, Anda harus dapat mengkompilasi ini, seperti halnya, dengan peringatan untuk menghasilkan executable yang melakukan apa yang dikatakan sumber WordMath.

LambdaBeta
sumber
2
Catatan: sayangnya ini gagal dengan beberapa kompiler saat Anda mengakhiri dengan pengulangan. Ini karena mereka melemparkan spasi setelah 0 dan kemudian melihat periode nyasar dan tidak tahu apa yang harus dilakukan dengan itu.
LambdaBeta
pintar, saya terkesan.
kucing
7

Retina, 170 byte

Karena siapa yang tidak mau melihat ini ?!

Saya memikirkan betapa hebatnya melihat solusi Retina, dan saya memutuskan untuk membuatnya dengan cepat. Hanya butuh satu jam. Seperti biasa, hitungan byte mengasumsikan penyandian ISO 8859-1.

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

Cobalah online

Output memiliki baris baru yang tidak boleh disalin ketika menguji program yang dihasilkan. Program ini tidak mendukung negatif, karena rentang integer standar Retina (dalam unary) tidak.

Penjelasan:

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

Program matematika:

Menambahkan:

Tambahkan jumlah yang ke awal. Tambahkan 5:

^
1111

Mengurangi:

Hapus jumlah yang dari awal. Kurangi 5:

^11111

Kurangi dari:

Ganti input 1dengan xs. Letakkan di sebelah nomor tetap. Hapus berulang kali x1. Kurangi dari 10:

1
x
$
1111111111
+`x1

Kalikan dengan:

Gantilah setiap orang 1dengan jumlah tertentu. Kalikan dengan 3:

1
111

Dibagi dengan:

Ini menggunakan program Retina saya untuk Divisi Integer . Bagi dengan 2:

^                   # 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
$*
mbomb007
sumber
Saya khawatir saya tidak melihat bagaimana ini bisa bekerja. Input apa pun yang saya coba untuk perintah pengurangan, saya mendapatkan hasil yang rusak (apakah ada umpan baris yang hilang dalam output?). Saya juga tidak melihat bagaimana ini menangani input negatif atau hasil antara negatif.
Martin Ender
@ MartinEnder Saya dapat memperbaiki pengurangan jika Anda menjelaskan mengapa program yang disederhanakan ini memberikan dua yang di output. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007
Karena $cocok di bagian paling akhir string atau di depan linefeed line. Anda perlu \zjika Anda hanya menginginkan yang pertama.
Martin Ender
4

GNU awk, 139 byte

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

Doa:

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

Kasus uji:

$> 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;
Rainer P.
sumber
4

Haskell, 232 231 byte

Tentu saja seorang programmer fungsional lebih suka mengembalikan fungsi daripada string yang mewakili suatu program, tetapi di sini kita mulai:

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

Keterangan: Kami selalu memulai dengan menambahkan nol, jika tidak, transpilasi dari program WordMath yang sepele tidak akan memberikan informasi yang cukup untuk menyimpulkan jenis yang readdigunakan. subtract from ndapat diimplementasikan sebagai (n-), tapi saya gunakan ((-)n)untuk lebih banyak keseragaman. Dalam hal subtract nsaya menyalin subtractdari input jadi saya tidak perlu menulisnya, tapi saya harus mengganti ruang yang hilang di bagian akhir. repeatdigunakan sebagai operasi default; bersama dengan operasi awal awal kosong ini memungkinkan untuk dengan mudah mengabaikan empat kata pertama.

Contoh penggunaan:

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

Contoh lain memberikan hasil sebagai berikut:

"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"
Sievers Kristen
sumber
Hanya ingin tahu, bagaimana Anda menghasilkan fungsi untuk kembali, bukan string?
Cyoce
Dalam bahasa pemrograman fungsional, membuat dan menyusun fungsi tidak lebih sulit daripada membuat dan menambahkan string. hmungkin terlihat seperti h s n r|x<-s.read.init$n=x%r.xdan dipanggil dengan argumen pertama fungsi seperti h(+)n r(dan perlu ada beberapa fliptempat untuk mendapatkan urutan operator yang benar), kasus dasar adalah _%_=id. Fungsi utama dapat menghindari semua boilerplate dan hanya menjadi t l=id%words l. - Berkat currying, itu mungkin dilihat sebagai penerjemah, dan gagasan itu mungkin mengarah pada solusi yang lebih mudah dan / atau lebih pendek.
Christian Sievers
4

Python 2, 263 258 260 221 byte

Ini mungkin masih bisa jauh lebih pendek.

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(','))

Cobalah online

Saya menggunakan //bukan /, karena instruksi terakhir akan memiliki .pada akhirnya, membuat angka apa pun menjadi mengambang. Jadi untuk menjaga agar divisi tetap konsisten, saya menggunakan divisi integer.

Output kasus uji:

print input()
print 9.-((input())//5)
print ((((((input())+5)+10)+10)-15)-15)//2.
print (((input())-1)-1)-1
mbomb007
sumber
Jika Anda mengubah blok besar ifs omenjadi yang berikut (yang menurut saya harusnya berfungsi) o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c]:, Anda bisa turun ke 224.
Kade
@Ade Ya, itu masih terbaca. Tidak dapat memiliki itu
mbomb007
@Cyoce Tidak, tindakan memanggil lambda mungkin lebih mahal daripada menghemat. Itu harus menyimpan 4 atau 5 byte per panggilan untuk melunasi.
mbomb007
4

Befunge, 342 305 byte

>~$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

Cobalah online!

Keluaran

Kode yang dihasilkannya dimulai dengan perintah &(nilai input), dan diakhiri dengan perintah .(nilai output) dan @(keluar). Di antara kita memiliki berbagai perhitungan dalam bentuk <number><operation>, di mana operasi dapat +(tambah), -(kurangi), /(bagi dengan), *(dikalikan dengan), dan \-(kurangi dari).

The jumlah itu sendiri adalah sedikit rumit, karena Befunge hanya mendukung literal numerik di kisaran 0 sampai 9, jadi segala sesuatu lebih besar dari kebutuhan yang dihitung secara manual. Karena kita sudah membaca angka-angka dalam karakter demi karakter, kita cukup membangun angka ketika setiap digit dibaca, jadi misalnya, 123 menjadi 155+*2+55+*3+, yaitu (((1 * 10) + 2) * 10) + 3.

Contohnya

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-.@

Penjelasan

Befunge tidak memiliki kemampuan untuk memanipulasi string, jadi sebagian besar parsing ditangani dengan menghitung karakter. Kita mulai hanya dengan melewatkan 18 karakter pertama, yang membuat kita melewati Think of a number number (ditambah koma atau titik). Kemudian jika karakter berikutnya adalah beberapa bentuk baris baru atau EOF kita langsung ke rutin output, jika tidak kita terus mencari daftar perintah.

Untuk mem-parsing perintah, kita terus menghitung karakter sampai kita mencapai angka atau pemisah. Jika itu pemisah, itu pasti perintah ulang yang kami tangani sebagai kasus khusus. Jika ini digit, kami menambahkannya ke buffer output, dan terus mencari digit lainnya. Setiap kali angka adalah output, kami awali dengan 55+*(untuk mengalikan total sejauh ini dengan 10) dan sufiks dengan +(untuk menambahkannya ke total). Setelah digit selesai kita tambahkan karakter perintah.

Adapun cara perintah ditentukan, kita mengambil jumlah karakter hingga modulo digit pertama 7. Untuk menambahkan ini adalah 4 (termasuk spasi berikut), untuk kurangi itu 2, untuk bagi dengan itu 3, untuk kalikan dengan itu 5 , dan untuk mengurangi dari 0. Kurangi dari memerlukan sedikit penanganan tambahan karena membutuhkan \-kombo perintah, tetapi yang lain hanya menggunakan nilainya untuk mencari karakter perintah yang sesuai dalam sebuah tabel.

Proses ini diulangi untuk setiap perintah, membangun output menjadi string yang telah dibangun sebelumnya pada baris 8. Setiap kali perintah tambahan ditambahkan, kami juga menambahkan kutipan penutup ke string untuk memastikan selalu diakhiri dengan benar. Kemudian ketika kita akhirnya mencapai akhir dari input kita, kita cukup "mengeksekusi" string ini untuk mendorongnya ke stack, kemudian ikuti itu dengan urutan output standar untuk menuliskan semuanya.

James Holderness
sumber
3

JavaScript (ES6), 163 byte

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)`

Cobalah:

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)
*/

Darrylyeo
sumber
3

Vim 208 171 168 byte

Menambahkan kemampuan untuk melakukan beberapa pengulangan berturut-turut seperti pada @ Flp.Tkc tetapi golf cukup byte sehingga saya masih bisa menurunkan jumlah byte.

: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

Karakter yang tidak dapat dicetak:

: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^[^[

Output kasus uji:

  1. cw^R=^R" ^[ TryItOnline
  2. cw^R=((^R" /5) *-1+9) ^[ TryItOnline
  3. cw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[ TryItOnline
nmjcman101
sumber
Ini sepertinya tidak berhasil untuk beberapa pengulangan yang berurutan.
FlipTack
@ Flp.Tkc diperbaiki, terima kasih! Saya tidak memperhatikan itu sebelumnya.
nmjcman101
2

lex, 246 byte

%{
#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 menargetkan ke C, jadi kompiler C perlu mengkompilasinya menjadi sesuatu yang dapat dieksekusi. Pustaka lexer ( ll) juga perlu ditautkan. Ini dapat menambahkan byte-penalti, tetapi saya tidak yakin berapa byte jika demikian.

Program ini menghasilkan program lex (per spesifikasi) yang mengevaluasi ekspresi wordmath yang di-transpilasikan. Kode antara %{dan %}hanya untuk "transpiler":

#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 */

Antara dua %%baris adalah bagian regex / action. Aturan pertama yang harus dicocokkan adalah T("Pikirkan ...") yang membangun mukadimah (paling sedikit program lex harus memuat bagian aturan setidaknya, dan yytextmerupakan teks yang cocok terakhir, sehingga aturan tersebut pada dasarnya menaburkan akumulator dengan input pengguna. ).

Program membuang semua masukan kecuali yang yang cocok, dan aturan-aturan lainnya ( ad, fr, sampai re) menangani klausa ekspresi wordmath dengan sebagai pertandingan seminimal mungkin untuk menjadi unik. Dalam sebagian besar dari ini, ia menetapkan cke infix ekspresi, yang akan digabungkan antara ndan bilangan bulat terakhir dibaca ketika Odipanggil (jadi misalnya, membaca "tambah 9" akan mengatur infiks menjadi +=, v ke 9, dan panggilan ke Oakan menampilkan n+=9;) . (Disamping yang menarik adalah bahwa "kurangi dari 8" akan menyebabkan keduanya sdan fraturannya cocok, tetapi karena Odipanggil hanya pada angka, aturan yang tepat n=-n+8;adalah satu-satunya ekspresi yang mendapat output). The reaturan untuk "repeat" hanya panggilanOlagi, yang menampilkan ekspresi yang terakhir dibuat (dan karena kecocokan berikutnya akan gagal yytext, mendukung "ulangi" adalah mengapa konversi integer dalam [0-9]+aturan diperlukan). Akhirnya, suatu periode menyebabkan trailer program menjadi output, yang hanya menampilkan akumulator dan ditutup dengan %%pasangan yang menunjukkan akhir dari program lex output.

Catatan: Program transpiler utama atau program keluaran tidak akan berakhir. Input perpipaan akan berfungsi, atau menyediakan EOF (ctrl-D). Jika penghentian diperlukan setelah input pertama, exit () s dapat ditambahkan.

Untuk membangun / menjalankan:

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
%

Tes 1:

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

Tes 2:

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

Tes 3:

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

Tes 4:

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

Pyth, 69 67 byte

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

Program yang mengambil input dari "quoted string"dan mencetak hasilnya.

Suite uji

Bagaimana itu bekerja

Pyth memiliki operator awalan, sehingga operasi aritmetika dasar dilakukan menggunakan (operator)(operand1)(operand2), sedangkan variabel pra-diinisialisasi Qmemberikan input. Oleh karena itu, program WordMath yang dibuat ulang dibangun dengan memulai dengan string 'Q', dan pada setiap tahap, membuat prap Operator, dan kemudian menambahkan atau menambahkan operan sebagai neccessary.

J\QAtur J, string program yang ditranskripsikan, ke string'Q'

tcQ\, Pisahkan input pada koma, dan buang elemen pertama (yaitu ' Think of a number')

V Untuk Nitu:

  • Iq@N1\r Jika karakter at N[1]is 'r'(repeat):
    • =NZSetel Nke Z(nilai sebelumnya N, atur di akhir for for loop)
  • x"asdm"@N1 Temukan indeks N[1]dalam "asdm"(tambah, kurangi, bagikan, gandakan)
  • @"+-/*" Indeks dengan itu menjadi "+-/*", memberikan operator yang dibutuhkan
  • ,J-eCN)\.Hasilkan daftar dua elemen [J, -eCN)\.], di mana elemen kedua adalah elemen terakhir dari Nperpecahan pada spasi putih dengan '.'karakter apa pun dihapus (operan)
  • qh@cN)1\f Jika karakter pertama dari elemen kedua Nsplit di whitespace adalah 'f'(kurangi dari):
    • .> Tukar elemen daftar dua elemen
  • + Gabungkan daftar operator dan dua elemen menjadi satu daftar
  • =Jjd Setel Jke yang bergabung di spasi
  • =ZN Setel ZkeN

J Mencetak J

TheBikingViking
sumber
Pria jawaban yang baik ... Mengilhami saya untuk mencoba di 05AB1E, yang ... Lebih menakutkan daripada yang diantisipasi.
Magic Gurita Guci
2

Pip , 58 byte

Sayang sekali saya belum mengimplementasikan operator reverse-pengurangan itu.

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

Program ini mengambil skrip WordMath dari stdin dan menampilkan kode Pip ke stdout. Kode yang merupakan keluaran, juga mengambil angka dari stdin dan menampilkan hasilnya ke stdout. Cobalah online!

Strategi

Untuk input seperti ini:

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

kami ingin output seperti ini:

YqYy*3Yy+1

yang berfungsi sebagai berikut:

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

Penjelasan + tidak dikelompokkan

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

Struktur dasar dari program ini adalah {...}Mq^k, yang membelah q(garis stdin) pada k(koma-ruang) dan Maps fungsi untuk setiap elemen.

Di dalam fungsi, kita mulai dengan menangani repeatkasing. Tes terpendek di Pip tampaknya sNa(apakah ada spasi di perintah). Jika demikian, kami ingin menggunakan a; jika tidak, gunakan p, yang menyimpan perintah sebelumnya. Tetapkan nilai itu kembali ke adan juga ke p(untuk waktu berikutnya).

Untuk nilai pengembalian kami, kami menggunakan daftar, yang baik-baik saja karena format output default untuk daftar adalah menyatukan semuanya. Hasilnya selalu dimulai dengan Y. Selanjutnya, kita perlu tabel pencarian untuk operasi.

Perhatikan bahwa panjang add (4), subtract (9), divide by (10), multiply by (12), dan subtract from (14) semuanya berbeda. Lebih jauh mengamati bahwa mereka masih berbeda ketika diambil mod 7. Dengan demikian, kita dapat menggunakannya untuk mengindeks ke dalam daftar tujuh elemen (berisi lima snipet kode dan dua penampung) untuk memetakan setiap perintah WordMath ke kode Pip yang sesuai (dirancang sedemikian sehingga jumlahnya dapat disatukan sampai akhir):

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

Untuk indeks, kita menggunakan regex untuk mendapatkan indeks dari digit pertama dalam perintah: a@?`\d`. Kami juga menarik regex yuntuk digunakan di masa depan. Tabel pencarian dihasilkan dengan memisahkan string "-y+ y- y// y+ y* "pada s(spasi).

Kami masih harus menangani entri pertama, yang harus diterjemahkan ke dalam kode Yq. Karena Think of a numbertidak mengandung digit apa pun, @?operator mengembalikan nol. Menggunakan nil sebagai indeks ke dalam tabel pencarian juga mengembalikan nil. Nil itu palsu, jadi yang perlu kita lakukan hanyalah menambah |'qpenggunaan qalih-alih operasi untuk kasus ini.

Elemen terakhir dari daftar yang dikembalikan adalah nomor itu sendiri. Kami memperoleh ini melalui a@y(temukan semua kecocokan dalam perintah digit regex yang kami tarik sebelumnya). Ini mengembalikan daftar digit, tetapi sekali lagi, itu tidak masalah karena semua daftar akan digabungkan ketika output. Untuk entri pertama, a@ytidak cocok dengan digit dan memberikan daftar kosong, yang tidak menambahkan apa pun ke output.

Sebagai contoh

Dengan input

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

ekspresi peta memberikan daftar

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

yang, ketika digabungkan, output

YqY-y+20Yy+2Yy+2
DLosc
sumber
2

Python 2 , 154 153 146 byte

Memperbaiki, dan bahkan menyimpan beberapa byte dalam proses. ^ __ ^

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"

Cobalah online!

Berdasarkan strategi yang sama dengan jawaban Pip saya . Fitur khusus python:

  • Think of dan penutup .dihapus dari string sebelum pemisahan ( input()[9:-1]). Periode itu terlalu sial untuk ditangani dalam loop utama. Menghapus sembilan karakter pertama membantu karena alasan yang berbeda (lihat di bawah).
  • Alih-alih mendapatkan panjang setiap perintah dengan regex-mencari digit (mahal karena Python import re), kita gunakan rfind(" ")untuk menemukan ruang terakhir dalam perintah. Kami juga dapat menggunakan ini untuk memeriksa repeatkasus ini.
  • Python tidak memiliki pengindeksan siklus Pip, jadi kita harus mengambil indeks mod 7 secara eksplisit. Di sisi lain, ini berarti bahwa kita dapat menghapus nilai dummy terakhir dalam tabel pencarian, karena indeks mod 7 tidak pernah 6.
  • "Perintah" yang pertama kali dilalui adalah a number, di mana indeks ruangnya 1. Indeks ini dengan mudah mengisi lubang lain di tabel pencarian. Masalah lain dengan memproses tahap input dalam loop utama adalah +c[s:]bagian, yang akan menghasilkan x=input() number. Untuk mengatasi masalah itu, kami mengalikan dengan c[0]<"a": 1untuk semua perintah biasa, yang cdimulai dengan spasi, tetapi 0untuk yang awal a number.
DLosc
sumber
1

WinDbg, 449 388 byte

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 ."

-61 byte dengan mendefinisikan alias untuk kode yang diulang

Terinspirasi oleh penggunaan LambdaBeta untuk#define . Pendekatan ini memodifikasi sintaksis WordMath sedikit ( ,dan .harus dibatasi ruang seperti kata-kata lain, dan ,tidak mengikuti repeat), dan membuat alias sehingga sintaksis WordMath yang dimodifikasi adalah kode WinDbg yang valid. Baris terakhir melakukan apa yang ditanyakan dan diubah oleh pertanyaan dengan mengubah input menjadi sintaks yang dimodifikasi.

Input diambil dengan mengatur string pada alamat memori dan mengatur pseudo-register $t0ke alamat itu. Catatan: ini akan menimpa intat 0x2000000, jadi jika Anda memulai string Anda di sana, itu akan ditimpa sebagian. $t0juga akan ditimpa.

Karena itu membuat alias, tergantung pada apakah kode ini telah berjalan sebelum atau setelah pengaturan string, kode output akan berbeda (baik alias atau tidak). Sayangnya, saya tidak menemukan cara untuk membuat alias berkembang dengan baik tanpa dibatasi spasi (artinya skrip WordMath tidak bisa dieksekusi secara langsung tanpa ditransformasikan terlebih dahulu).

Bagaimana itu bekerja:

* $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 " ."

Contoh output, memasukkan string sebelum menjalankan kode ini satu kali (program yang dihasilkan menyerupai WordMath):

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

Contoh output, memasukkan string setelah setelah kode ini dijalankan sekali (alias diperluas ketika memasukkan string sehingga program yang dihasilkan tidak cantik):

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

Beberapa keluaran sampel lagi, hanya menggunakan sintaks WordMath yang sedikit dimodifikasi:

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
susu
sumber
0

Scala, 338 byte

Cobalah sendiri di ideone

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)")}

Penjelasan:

// 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)")
}
corvus_192
sumber