Phiên dịch WordMath


25

Chúng ta đều đã thấy những "toán học hax" trực tuyến trông như thế này:

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

Và, bằng phép thuật, mọi người kết thúc với số 8!


Ngôn ngữ

Hãy xác định một ngôn ngữ lập trình sử dụng cú pháp của văn bản trên, được gọi là "WordMath". Các tập lệnh WordMath theo mẫu này:

Think of a number, <commandlist>.

Về cơ bản có nghĩa là: Lấy một số (làm đầu vào từ STDIN) làm bộ tích lũy ban đầu, thực hiện tất cả các lệnh trên nó và xuất kết quả.

Các lệnh được phân tách bằng dấu phân cách ,(dấu phẩy + dấu cách). Các lệnh hợp lệ là (lưu ý #đại diện cho một số nguyên không âm :) :

  • add #/ subtract #- Cộng / trừ giá trị từ bộ tích lũy.
  • divide by #/ multiply by #- floordiv / nhân số tích lũy với giá trị đã cho.
  • subtract from #- Tương tự subtract, nhưng acc = # - accthay vìacc = acc - #
  • repeat- làm lệnh cuối cùng một lần nữa. Đây không thể là lệnh đầu tiên, nhưng bạn phải hỗ trợ nhiều lần lặp lại liên tiếp.

Các thách thức

Nhiệm vụ của bạn là tạo một chương trình hoặc chức năng lấy tập lệnh WordMath hợp lệ làm đầu vào và chuyển mã thành chương trình đầy đủ hợp lệ - trong cùng ngôn ngữ mà mã của bạn đang sử dụng.

Ví dụ: nếu mã của tôi nằm trong Python 2 và tập lệnh là:

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

Chương trình xuất ra có thể là:

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

Hay cách khác:

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

Miễn là nó là một chương trình đầy đủ lấy đầu vào từ STDINvà in ra STDOUT, hoặc tương đương gần nhất của ngôn ngữ.


Quy tắc

  • Chương trình ban đầu của bạn có thể cho rằng đầu vào luôn là tập lệnh WordMath hợp lệ.
  • Các chương trình được dịch mã không phải xử lý các lỗi toán học như chia cho 0.
  • Các chương trình được dịch mã có thể cho rằng đầu vào đại diện cho một số nguyên được ký hợp lệ, trong phạm vi số nguyên tiêu chuẩn của ngôn ngữ của bạn.
  • Đây là , vì vậy giải pháp ngắn nhất (tính bằng byte) sẽ thắng.
  • Chỉ có số byte của chương trình gốc của bạn có vấn đề - mã xuất ra có thể miễn là bạn muốn!

Ví dụ tập lệnh

Ví dụ 1:

Think of a number. 

Hãy nhập liệu, không làm gì, hiển thị nó: chương trình con mèo của WordMath.

Ví dụ 2:

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

Hãy nhớ rằng "chia" là phân chia sàn, vì vậy đối với chương trình này 6 -> 8, và 29 -> 4.

Ví dụ 3:

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

Chương trình mèo mở rộng!

Ví dụ 4:

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

Lấy một số và trừ 3.


Chúng ta có phải hỗ trợ lặp lại liên tiếp không?
darrylyeo

1
Chúng ta có thể sử dụng số float khi đó là loại mặc định của ngôn ngữ / nếu nó không hỗ trợ số nguyên?
Rainer P.

@RainerP. chỉ khi ngôn ngữ không hỗ trợ số nguyên / phân chia số nguyên
FlipTack

1
Kết quả mong đợi là -5/3gì? Chúng ta làm tròn hướng tới 0hoặc hướng tới vô cực tiêu cực?
Martin Ender

1
@MartinEnder Tôi sẽ nói vòng về phía vô cực âm như là phân chia tầng , nhưng nếu ngôn ngữ của bạn thực hiện phân chia số nguyên về 0 thì cũng tốt.
FlipTack

Câu trả lời:


6

05AB1E , 59 56 54 52 byte

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

Hãy thử trực tuyến!

Não tôi đau như địa ngục sau đó ... Nó xuất ra mã 05AB1E như sau:

  • Think of a Number được loại bỏ, do đầu vào ngầm.
  • Subtract From #lông để #s-(swap abvà thực hiện thao tác).
  • Subtract #chuyển đổi thành #-.
  • Add #chuyển đổi thành #+.
  • Multiply by #chuyển đổi thành #*.
  • Divide by #chuyển đổi thành #/.
  • Repeat lấy bất cứ thứ gì được lưu trữ cuối cùng trong sổ đăng ký và ghép nó lại.

Giải thích:

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

Thí dụ:

Đầu vào:

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

Đầu ra:

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

Thử giải pháp với đầu vào là 10:

Hãy thử trực tuyến!

Xem nó trên google:

Đây là một liên kết đến cùng phương trình được gõ vào google.


13

C Tiền xử lý, 362 byte

Tôi đã làm việc này trong JUST bộ tiền xử lý C, nhưng lệnh lặp lại hóa ra quá khó để thực hiện. Vì vậy, thay vào đó tôi đã sử dụng bộ tiền xử lý để biến đầu vào thành một mảng sau đó được diễn giải bằng một số mã bổ sung.

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

Đầu vào phải được cung cấp trong "input.wm" hoặc chỉ được đổ vào nguồn tại dòng đó. Tôi đã bao gồm các byte của nó trong số của tôi bởi vì tôi cho rằng nó hơi hack và hơi trái với các quy tắc của thách thức, vì vậy nó chỉ phù hợp.

Dù sao, một khi bạn đổ nguồn WordMath của bạn vào input.wm nơi trình biên dịch có thể tìm thấy nó, bạn sẽ có thể biên dịch nó, như là, với các cảnh báo để tạo ra một tệp thực thi đúng như nguồn WordMath nói.


2
Lưu ý: điều này không may thất bại với một số trình biên dịch khi bạn kết thúc bằng lặp lại. Điều này là do họ ném một khoảng trắng sau 0 và sau đó thấy một khoảng thời gian đi lạc và không biết phải làm gì với nó.
LambdaBeta

thông minh, tôi ấn tượng.
con mèo

7

Võng mạc, 170 byte

Bởi vì ai sẽ không muốn thấy điều này?!

Tôi đã nghĩ rằng sẽ tuyệt vời thế nào khi thấy một giải pháp Retina và tôi đã quyết định tạo ra nó một cách nhanh chóng. Chỉ mất một giờ. Như thường lệ, số byte giả định mã hóa 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

Dùng thử trực tuyến

Đầu ra có một dòng mới không nên được sao chép khi kiểm tra chương trình kết quả. Chương trình không hỗ trợ phủ định, bởi vì phạm vi số nguyên tiêu chuẩn của Retina (không đồng nhất) thì không.

Giải trình:

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

Các chương trình toán:

Thêm vào:

Thêm số lượng những người bắt đầu. Thêm 5:

^
1111

Trừ:

Loại bỏ số lượng từ đầu. Trừ 5:

^11111

Trừ đi từ:

Thay 1s đầu vào bằng xs. Đặt bên cạnh số cố định. Liên tục gỡ bỏ x1. Trừ từ 10:

1
x
$
1111111111
+`x1

Nhân với:

Thay thế mỗi 1với một số lượng nhất định của họ. Nhân với 3:

1
111

Chia cho:

Điều này sử dụng chương trình Retina của tôi cho Bộ phận Integer . Chia cho 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
$*

Tôi sợ tôi không thấy làm thế nào điều này có thể làm việc. Bất cứ đầu vào nào tôi thử cho các lệnh trừ, tôi đều nhận được kết quả bị hỏng (có thiếu nguồn cấp trong đầu ra không?). Tôi cũng không thấy cách này xử lý đầu vào tiêu cực hoặc kết quả trung gian âm.
Martin Ender

@MartinEnder Tôi có thể sửa lỗi trừ nếu bạn giải thích lý do tại sao chương trình đơn giản hóa này cung cấp hai cái ở đầu ra. retina.tryitonline.net/#code=JArCtjE&input=dGVzdAo
mbomb007

Bởi vì $khớp ở cuối chuỗi hoặc trước một dòng cấp dữ liệu. Bạn cần \znếu bạn chỉ muốn trước đây.
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

Cầu nguyện:

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

Các trường hợp thử nghiệm:

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

Tất nhiên một lập trình viên chức năng muốn trả về một hàm hơn là một chuỗi đại diện cho một chương trình, nhưng ở đây chúng tôi đi:

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

Lưu ý: Chúng tôi luôn bắt đầu bằng cách thêm số không, nếu không, việc dịch mã chương trình WordMath tầm thường sẽ không cung cấp đủ thông tin để suy ra loại readđược sử dụng. subtract from ncó thể được thực hiện như (n-), nhưng tôi sử dụng ((-)n)cho đồng bộ hơn. Trong trường hợp subtract ntôi sao chép subtracttừ đầu vào để tôi không phải viết nó, nhưng tôi cần phải bù vào chỗ trống ở cuối. repeatđược sử dụng làm hoạt động mặc định; cùng với một thao tác ban đầu trống trước, điều này cho phép dễ dàng bỏ qua bốn từ đầu tiên.

Ví dụ sử dụng:

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

Các ví dụ khác cho kết quả như sau:

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

Chỉ tò mò, làm thế nào bạn sẽ tạo ra một hàm để trả về thay vì một chuỗi?
Cyoce

Trong một ngôn ngữ lập trình chức năng, việc tạo và soạn thảo một hàm không khó hơn việc tạo và nối thêm một chuỗi. hcó thể trông giống như h s n r|x<-s.read.init$n=x%r.xvà được gọi với đối số đầu tiên là một hàm như h(+)n r(và cần phải có một số flipnơi để có được thứ tự toán tử chính xác), trường hợp cơ sở là _%_=id. Chức năng chính có thể tránh tất cả các nồi hơi và chỉ được t l=id%words l. - Nhờ cà ri, nó có thể được xem như một thông dịch viên, và ý tưởng đó có thể dẫn đến một giải pháp dễ dàng hơn và / hoặc ngắn hơn.
Christian Sievers

4

Python 2, 263 258 260 221 byte

Điều này có lẽ vẫn có thể ngắn hơn nhiều.

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

Dùng thử trực tuyến

Tôi sử dụng //thay vì /, bởi vì hướng dẫn cuối cùng sẽ có một .kết thúc, làm cho bất kỳ số nào nổi. Vì vậy, để giữ cho sự phân chia nhất quán, tôi sử dụng phép chia số nguyên.

Trường hợp thử nghiệm đầu ra:

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

Nếu bạn thay đổi điều đó khối lớn của ifs cho ođến sau (mà tôi nghĩ nên làm việc): o=[[o+[['+-'['s'in c],'//']['v'in c],'*']['m'in c]+n,n+'-'+o]['f'in c],'input()']['T'in c], bạn có thể lấy nó xuống 224.
Kade

@Kade Vâng, nó vẫn dễ đọc. Không thể có điều đó.
mbomb007

@Cyoce Không, chính hành động gọi lambda có lẽ sẽ tốn kém hơn tiết kiệm. Bạn phải tiết kiệm 4 hoặc 5 byte cho mỗi cuộc gọi để thanh toán.
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

Hãy thử trực tuyến!

Đầu ra

Mã mà nó tạo ra bắt đầu bằng lệnh &(giá trị đầu vào) và kết thúc bằng các lệnh .(giá trị đầu ra) và @(thoát). Ở giữa chúng ta có các phép tính khác nhau trong biểu mẫu <number><operation>, trong đó phép toán có thể là +(cộng), -(trừ), /(chia cho), *(nhân với) và \-(trừ từ).

Bản thân con số này hơi phức tạp, vì Befunge chỉ hỗ trợ các chữ số trong phạm vi từ 0 đến 9, do đó, bất cứ điều gì lớn hơn số đó cần phải được tính toán thủ công. Vì chúng ta đã đọc các số theo từng ký tự, chúng ta chỉ cần xây dựng số khi mỗi chữ số được đọc, vì vậy, ví dụ, 123 trở thành 155+*2+55+*3+, tức là (((1 * 10) + 2) * 10) + 3.

Ví dụ

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

Giải trình

Befunge không có khả năng điều khiển các chuỗi như vậy, vì vậy hầu hết các phân tích cú pháp được xử lý bằng cách đếm các ký tự. Chúng tôi bắt đầu chỉ bằng cách bỏ qua 18 ký tự đầu tiên, điều này giúp chúng tôi vượt qua Suy nghĩ về cụm từ số (cộng với dấu phẩy hoặc dấu chấm). Sau đó, nếu ký tự tiếp theo là một dạng dòng mới hoặc EOF, chúng ta sẽ đi thẳng đến thói quen đầu ra, nếu không chúng ta tiếp tục tìm kiếm một danh sách lệnh.

Để phân tích một lệnh, chúng ta chỉ cần tiếp tục đếm các ký tự cho đến khi chúng ta đạt được một chữ số hoặc dấu phân cách. Nếu đó là một dấu phân cách, nó phải là lệnh lặp lại mà chúng ta xử lý như một trường hợp đặc biệt. Nếu đó là một chữ số, chúng tôi thêm nó vào bộ đệm đầu ra và tiếp tục tìm kiếm thêm các chữ số. Mỗi khi một chữ số được xuất ra, chúng tôi đặt tiền tố cho nó 55+*(để nhân tổng số cho đến nay là 10) và +thêm vào đó (để thêm nó vào tổng số). Khi các chữ số kết thúc, chúng ta thêm ký tự lệnh.

Về cách xác định lệnh, chúng tôi lấy số lượng ký tự cho đến modulo chữ số đầu tiên 7. Để thêm đây là 4 (bao gồm cả không gian sau), để trừ đi 2, để chia cho 3, nhân với 5 và để trừ đi 0. Nó trừ yêu cầu xử lý bổ sung một chút vì nó cần tổ \-hợp lệnh, nhưng những cái khác chỉ sử dụng giá trị của chúng để tra cứu ký tự lệnh thích hợp trong bảng.

Quá trình này được lặp lại cho mỗi lệnh, xây dựng đầu ra thành một chuỗi được cấu trúc sẵn trên dòng 8. Mỗi lần thêm một lệnh, chúng tôi cũng thêm một trích dẫn đóng vào chuỗi để đảm bảo rằng nó luôn luôn được kết thúc đúng. Sau đó, khi cuối cùng chúng ta đạt đến cuối của đầu vào, chúng ta chỉ cần "thực thi" chuỗi này để đẩy nó lên ngăn xếp, sau đó làm theo chuỗi đó với một chuỗi đầu ra tiêu chuẩn để viết ra tất cả.


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

Thử nó:

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 byte

Đã thêm khả năng thực hiện nhiều lần lặp lại liên tiếp theo @ Flp.Tkc nhưng đã loại bỏ đủ số byte mà tôi vẫn có thể hạ thấp số 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

Dùng thử

Ký tự không thể in:

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

Trường hợp thử nghiệm đầu ra:

  1. cw^R=^R" ^[ Dùng thử
  2. cw^R=((^R" /5) *-1+9) ^[ Dùng thử
  3. cw^R=((((((^R" +5) +10) *2) -15) -15) /2) ^[ Dùng thử

Điều này dường như không hoạt động cho nhiều lần lặp lại liên tiếp.
FlipTack

@ Flp.Tkc đã sửa, cảm ơn bạn! Tôi đã không nhận thấy điều đó sớm hơn.
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 nhắm mục tiêu đến C, vì vậy một trình biên dịch C sẽ cần phải biên dịch nó thành một cái gì đó có thể thực thi được. Thư viện lexer ( ll) cũng cần phải được liên kết. Điều này có thể thêm một hình phạt byte, nhưng tôi không chắc có bao nhiêu byte nếu vậy.

Chương trình xuất ra một chương trình lex (theo thông số kỹ thuật) để đánh giá biểu thức wordmath được phiên mã. Mã giữa %{%}chỉ dành cho "bộ chuyển đổi":

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

Giữa hai %%dòng là phần regex / hành động. Quy tắc đầu tiên được so khớp sẽ là T("Suy nghĩ ...") xây dựng phần mở đầu (các chương trình lex phải bắt đầu chứa ít nhất phần quy tắc và yytextlà văn bản phù hợp cuối cùng, do đó, về cơ bản, quy tắc này sẽ tạo ra bộ tích lũy với đầu vào của người dùng ).

Các vứt bỏ chương trình tất cả các đầu vào trừ cho rằng đó là lần xuất hiện, và các quy tắc khác ( ad, fr, lên đến re) xử lý các khoản biểu wordmath với như tối thiểu một trận đấu càng tốt phải là duy nhất. Trong hầu hết các trường hợp này, nó đặt cthành một phần tử biểu thức, được nối giữa nvà số nguyên cuối cùng được đọc khi Ođược gọi (ví dụ: đọc "add 9" sẽ đặt infix thành +=, v thành 9và lệnh gọi Osẽ xuất n+=9;) . (Một điều thú vị là "trừ 8" sẽ khiến cả quy tắc sfrquy tắc được khớp với nhau, nhưng vì Ochỉ được gọi ở số, quy tắc phù hợp n=-n+8;là biểu thức duy nhất có đầu ra). Các requy tắc cho "lặp lại" chỉ cuộc gọiOmột lần nữa, đưa ra biểu thức được tạo cuối cùng (và vì các kết quả khớp tiếp theo sẽ bị ghi đè yytext, hỗ trợ "lặp lại" là lý do tại sao phải chuyển đổi số nguyên trong [0-9]+quy tắc). Cuối cùng, một khoảng thời gian làm cho đoạn giới thiệu chương trình được xuất ra, nó chỉ xuất ra bộ tích lũy và đóng lại với %%cặp biểu thị sự kết thúc của chương trình lex đầu ra.

Lưu ý: Cả chương trình transpiler chính hoặc chương trình đầu ra sẽ chấm dứt. Đầu vào đường ống trong sẽ hoạt động hoặc cung cấp EOF (ctrl-D). Nếu chấm dứt là bắt buộc sau đầu vào đầu tiên, có thể thêm exit ().

Để xây dựng / chạy:

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
%

Kiểm tra 1:

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

Bài kiểm tra 2:

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

Bài kiểm tra 3:

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

Bài kiểm tra 4:

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

2

Pyth, 69 67 byte

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

Một chương trình lấy đầu vào của a "quoted string"và in kết quả.

Bộ kiểm tra

Làm thế nào nó hoạt động

Pyth có các toán tử tiền tố, vì vậy các hoạt động số học cơ bản được thực hiện bằng cách sử dụng (operator)(operand1)(operand2), trong khi biến khởi tạo trước Qcho đầu vào. Do đó, một chương trình WordMath được dịch mã được xây dựng bằng cách bắt đầu với chuỗi 'Q'và ở mỗi giai đoạn, chuẩn bị cho toán tử, sau đó trả trước hoặc nối thêm toán hạng là cần thiết.

J\QĐặt J, chuỗi chương trình được phiên mã, thành chuỗi'Q'

tcQ\, Tách đầu vào trên dấu phẩy và loại bỏ phần tử đầu tiên (đó là ' Think of a number')

VNtrong đó:

  • Iq@N1\r Nếu ký tự tại N[1]'r'(lặp lại):
    • =NZĐặt Nthành Z(giá trị trước đó của N, được đặt ở cuối vòng lặp for)
  • x"asdm"@N1 Tìm chỉ số của N[1]trong "asdm"(cộng, trừ, chia, nhân)
  • @"+-/*" Lập chỉ mục với điều đó "+-/*", đưa ra toán tử cần thiết
  • ,J-eCN)\.Mang lại danh sách hai phần tử [J, -eCN)\.], trong đó phần tử thứ hai là phần tử cuối cùng được Nphân tách trên khoảng trắng với bất kỳ '.'ký tự nào bị xóa (toán hạng)
  • qh@cN)1\f Nếu ký tự đầu tiên của phần tử Nphân chia thứ hai trên khoảng trắng là 'f'(trừ đi):
    • .> Hoán đổi các yếu tố của danh sách hai yếu tố
  • + Hợp nhất toán tử và danh sách hai thành phần vào một danh sách
  • =Jjd Đặt Jthành tham gia trên không gian
  • =ZN Đặt ZthànhN

J In J


Người đàn ông trả lời tốt đẹp ... Truyền cảm hứng cho tôi để thử trong 05AB1E, mà ... Đáng sợ hơn dự đoán.
Bạch tuộc ma thuật Urn

2

Pip , 58 byte

Quá tệ Tôi chưa thực hiện toán tử trừ ngược đó.

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

Chương trình lấy một tập lệnh WordMath từ stdin và xuất mã Pip thành thiết bị xuất chuẩn. Mã đó là đầu ra, tương tự, lấy một số từ stdin và đưa kết quả ra thiết bị xuất chuẩn. Hãy thử trực tuyến!

Chiến lược

Đối với đầu vào như thế này:

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

chúng tôi muốn đầu ra như thế này:

YqYy*3Yy+1

hoạt động như sau:

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 + giải thích

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

Cấu trúc cơ bản của chương trình là {...}Mq^k, phân tách q(một dòng stdin) trên k(dấu phẩy-không gian) và Maps một hàm cho mỗi phần tử.

Bên trong chức năng, chúng tôi bắt đầu bằng cách xử lý repeattrường hợp. Thử nghiệm ngắn nhất trong Pip dường như là sNa(có một khoảng trắng trong lệnh). Nếu vậy, chúng tôi muốn sử dụng a; nếu không, sử dụng p, lưu trữ lệnh trước đó. Gán giá trị đó trở lại avà cũng cho p(cho lần tiếp theo).

Đối với giá trị trả về của chúng tôi, chúng tôi sử dụng một danh sách, điều này là tốt vì định dạng đầu ra mặc định cho danh sách là nối mọi thứ lại với nhau. Kết quả luôn luôn bắt đầu với Y. Tiếp theo, chúng ta cần một bảng tra cứu cho các hoạt động.

Quan sát rằng độ dài của add (4), subtract (9), divide by (10), multiply by (12) và subtract from (14) đều khác biệt. Quan sát thêm rằng chúng vẫn khác biệt khi sử dụng mod 7. Vì vậy, chúng ta có thể sử dụng chúng để lập chỉ mục vào danh sách bảy yếu tố (chứa năm đoạn mã và hai trình giữ chỗ) để ánh xạ mỗi lệnh WordMath sang mã Pip thích hợp (được thiết kế sao cho số có thể chỉ đơn giản là nối đến cuối):

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

Đối với các chỉ số, chúng tôi sử dụng regex để lấy chỉ mục của chữ số đầu tiên trong lệnh : a@?`\d`. Chúng tôi cũng đã đưa regex vào ysử dụng trong tương lai. Bảng tra cứu được tạo bằng cách tách chuỗi "-y+ y- y// y+ y* "trên s(dấu cách).

Chúng ta vẫn phải xử lý mục nhập đầu tiên, nên dịch thành mã Yq. Vì Think of a numberkhông chứa bất kỳ chữ số nào, @?toán tử trả về nil. Sử dụng nil làm chỉ mục vào bảng tra cứu cũng trả về nil. Nil là giả, vì vậy tất cả những gì chúng ta cần làm là thêm |'qvào sử dụng qthay vì thao tác cho trường hợp này.

Phần tử cuối cùng của danh sách được trả về là chính số đó. Chúng tôi có được điều này thông qua a@y(tìm tất cả các kết quả khớp trong lệnh của biểu thức chính mà chúng tôi đã thực hiện trước đó). Điều này trả về một danh sách các chữ số, nhưng một lần nữa, nó không phải là vấn đề vì tất cả các danh sách sẽ được nối với nhau khi đầu ra. Đối với mục đầu tiên, a@ykhông khớp với các chữ số và đưa ra danh sách trống, không thêm bất cứ thứ gì vào đầu ra.

Ví dụ

Với đầu vào

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

biểu thức bản đồ đưa ra danh sách

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

mà, khi nối, đầu ra

YqY-y+20Yy+2Yy+2

2

Python 2 , 154 153 146 byte

Đã sửa lỗi và thậm chí lưu một vài byte trong tiến trình. ^ __ ^

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"

Hãy thử trực tuyến!

Dựa trên chiến lược giống như câu trả lời Pip của tôi . Các tính năng dành riêng cho Python:

  • Think of và việc đóng .được xóa khỏi chuỗi trước khi tách ( input()[9:-1]). Khoảng thời gian quá phiền phức để xử lý trong vòng lặp chính. Xóa chín ký tự đầu tiên sẽ giúp cho một lý do khác (xem bên dưới).
  • Thay vì lấy độ dài của mỗi lệnh bằng cách tìm kiếm regex cho một chữ số (đắt tiền bằng Python vì import re), chúng tôi sử dụng rfind(" ")để tìm khoảng trống cuối cùng trong lệnh. Chúng tôi cũng có thể sử dụng điều này để kiểm tra repeattrường hợp.
  • Python không có lập chỉ mục theo chu kỳ của Pip, vì vậy chúng tôi phải lấy chỉ mục mod 7 một cách rõ ràng. Mặt khác, điều này có nghĩa là chúng ta có thể loại bỏ giá trị giả cuối cùng trong bảng tra cứu, vì chỉ số mod 7 không bao giờ là 6.
  • "Lệnh" lần đầu tiên thông qua là a number, trong đó chỉ mục của không gian là 1. Chỉ số này thuận tiện lấp đầy lỗ khác trong bảng tra cứu. Vấn đề khác với việc xử lý giai đoạn đầu vào trong vòng lặp chính là +c[s:]phần, điều này sẽ dẫn đến x=input() number. Để giải quyết vấn đề đó, chúng tôi nhân chuỗi bằng c[0]<"a": 1cho tất cả các lệnh thông thường, cbắt đầu bằng khoảng trắng, nhưng 0cho ký tự đầu tiên a number.

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 bằng cách xác định bí danh cho mã lặp lại

Lấy cảm hứng từ việc sử dụng LambdaBeta#define . Cách tiếp cận này sửa đổi cú pháp WordMath một chút ( ,.phải được phân cách bằng dấu cách như các từ khác và ,không tuân theo repeat) và tạo bí danh sao cho cú pháp WordMath được sửa đổi là mã WinDbg hợp lệ. Dòng cuối cùng thực hiện những gì câu hỏi yêu cầu và phiên mã bằng cách chuyển đổi đầu vào thành cú pháp được sửa đổi.

Đầu vào được lấy bằng cách đặt một chuỗi tại một địa chỉ bộ nhớ và đặt thanh ghi giả $t0cho địa chỉ đó. Lưu ý: điều này sẽ ghi đè lên inttại 0x2000000, vì vậy nếu bạn bắt đầu chuỗi của mình ở đó, nó sẽ bị ghi đè một phần. $t0cũng sẽ bị ghi đè.

Bởi vì nó tạo ra các bí danh, tùy thuộc vào việc mã này đã chạy trước hay sau khi thiết lập chuỗi teh, mã đầu ra sẽ khác nhau (có bí danh hay không). Thật không may, tôi đã không tìm ra cách để các bí danh mở rộng đúng cách mà không bị giới hạn khoảng trắng (có nghĩa là tập lệnh WordMath không thể được thực thi trực tiếp mà không được chuyển đổi trước).

Làm thế nào nó hoạt động:

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

Đầu ra mẫu, nhập chuỗi trước khi chạy mã này một lần (chương trình kết quả giống với 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

Đầu ra mẫu, nhập chuỗi sau khi mã này đã chạy một lần (các bí danh được mở rộng khi nhập chuỗi để chương trình kết quả không đẹp bằng):

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

Một số đầu ra mẫu khác, chỉ cần sử dụng cú pháp WordMath được sửa đổi một chút:

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 byte

Hãy thử nó tại 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)")}

Giải trình:

// 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)")
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.