Xây dựng trình thông dịch cho ngôn ngữ không tồn tại


18

Xây dựng một trình thông dịch cho một ngôn ngữ giả, dựa trên ngăn xếp để có một đầu vào, giải thích nó và đưa ra kết quả dưới dạng một mảng các số. Nó sẽ lặp qua từng byte và thực hiện một chức năng khác nhau dựa trên bảng này:

0000 (0): Ghép (Kết hợp hai số trên cùng trong một ngăn xếp như thể chúng là một chuỗi. Ví dụ: 12,5 -> 125)
0001 (1): Tăng (Thêm 1 vào số trên đầu ngăn xếp)
0010 (2): Giảm (Trừ một từ số ở đầu ngăn xếp)
0011 (3): Nhân (Nhân hai số trên cùng trong ngăn xếp)
0100 (4): Chia (Chia số thứ 2 cho số trên cùng số trên cùng của ngăn xếp)
0101 (5): Thêm (Thêm hai số trên cùng vào ngăn xếp)
0110 (6): Trừ (Trừ số trên cùng của ngăn xếp từ số bên dưới nó)
0111 (7): Số mũ ( Tính số thứ hai từ trên xuống theo lũy thừa của số trên cùng)
1000 (8): Mô-đun: (Tìm số thứ hai từ trên xuống dưới modulo số trên cùng)
1001 (9): Xoay phải (Chuyển ngăn xếp xuống một. Số ở dưới cùng hiện ở trên cùng)
1010 (A): Xoay trái (Chuyển chồng lên trên một. Số ở trên cùng hiện ở dưới cùng)
1011 (B): Sao y (Sao chép số trên cùng để nó xuất hiện hai lần. Ví dụ: 4,1 trở thành 4,1,1)
1100 (C): Nhân đôi (Sao chép hai số trên cùng trên ngăn xếp. Ví dụ: 4, 1,2 trở thành 4,1,2,1,2)
1101 (D): Hoán đổi (Hoán đổi hai số trên cùng trên ngăn xếp. Ví dụ: 4,1,2 trở thành 4,2,1)
1110 (E): Nhân đôi Hoán đổi (Hoán đổi hai số trên cùng với hai số bên dưới chúng.ex: 1,2,3,4,5 trở thành 1,4,5,2,3)
1111 (F): Xóa / Pop (Xóa số ở đầu ngăn xếp)

Ví dụ: một tệp chứa

1 1 BC 5 C 5 B 9 5 - Đầu vào (hex)
| | | | | | | | | |
1 2 2 2 4 4 6 6 2 8 - Chồng
    2 2 2 2 4 6 6 6
      2 2 4 2 4 6 4
      2 2 2 2 4 2
          2 2 2

sẽ xuất [8,6,4,2]

Quy tắc:

  • Unicode / ký hiệu là được, nhưng ASCII là tốt nhất.
  • Sáng tạo! Tính ngắn gọn, nhưng sáng tạo là tuyệt vời!
  • Nếu byte quá cứng, hãy sử dụng "$iv*/+-^%><dtsz."hoặc "0123456789ABCDEF"thay vì byte thực tế.
  • TỐC ĐỘ! Càng nhanh càng tốt.
  • Điểm số dựa trên danh tiếng, nhưng kích thước là một yếu tố rất lớn.

Tặng kem:

Cố gắng hoàn thành thử thách này bằng cách sử dụng trình thông dịch mới được tạo của bạn trong một chuỗi càng ngắn càng tốt.

Ghi chú:

Điều làm cho thách thức này trái ngược với các thử thách chơi gôn mã khác là không có mã nào để thực hiện điều này. Nếu, giả sử, bạn phải viết một trình thông dịch brainf * ck, bạn có thể xem các triển khai của người khác. Với điều này, bạn không thể làm điều đó.


Tôi quên đặt và kết thúc ngày này. Tôi đoán tôi sẽ làm được một tháng kể từ khi tôi tạo ra thứ này. Người có số phiếu cao nhất vào ngày 22 tháng 2 sẽ thắng!


1
Nếu bạn nói rằng người chiến thắng được quyết định bằng phiếu bầu, thì đó là một cuộc thi phổ biến , không phải là môn đánh gôn .
Ry-

8
Nó không còn tồn tại nữa phải không? :)
Kendall Frey

1
Về mặt kỹ thuật , một ngôn ngữ không cần một trình thông dịch hoặc trình biên dịch để trở thành một ngôn ngữ. : P
Kendall Frey

2
IIUC, chúng ta nên bắt đầu với một ngăn xếp trống và coi dòng chảy dưới dạng số không?
John Dvorak

2
Bạn nên bắt đầu bằng một số 0 trên ngăn xếp (Vì không có cách nào để làm bất cứ điều gì nếu không có số để bắt đầu). Tôi sẽ để lại những điều ngầm cho bạn. Bất cứ điều gì dễ dàng hơn.
Tacovy

Câu trả lời:


14

Ruby, 67 dòng thay thế regex

Tôi quyết định viết trình thông dịch trong regex, đồng thời bám sát các thuật toán hiệu quả.

Tôi có thể đã sử dụng byte đơn giản, nhưng theo tôi, việc sử dụng các ký hiệu làm cho mã dễ đọc hơn. Tất nhiên, nếu chúng ta có thể gói hai hướng dẫn trong một byte ...

Kết hợp các giá trị âm dẫn đến hành vi bổ sung của mười, phản ánh biểu diễn bên trong.

Phân chia là phân chia số nguyên và phần còn lại không bao giờ âm.

subs = [
  # stack expansion
  [/^ ?([$iv*\/+\-^%dtsz.])/,  ' 0 \1'  ],
  [/^ (\d+ [$*\/+\-^%tsz])/,   ' 0 \1'  ],
  [/^ ((\d+ ){2,3}z)/,         ' 0 \1'  ],
  [/ (0|9)\1+/,                ' \1'    ],
  # concatenation
  [/ (\d+) (?:0+|9+)(\d+) \$/, ' \1\2 ' ], 
  [/ (\d+) (0|9) \$/,          ' \1\2 ' ],
  # swaps
  [/ ((?:\d+ )*)(\d+) </,      ' \2 \1' ],
  [/ (\d+)((?: \d+)*) >/,      '\2 \1 ' ],
  [/ (\d+) (\d+) s/,           ' \2 \1 '],
  [/ (\d+ \d+) (\d+ \d+) z/,   ' \2 \1 '],
  # dups
  [/ (\d+) d/,                 ' \1 \1 '],
  [/ (\d+ \d+) t/,             ' \1 \1 '],
  # pop
  [/ (\d+) \./,                ' '      ],

  # increment / decrement
  [/ (\d+) i/, ' \1I '], [/ (\d+) v/, ' \1V '],
  *(%w[0I 1I 2I 3I 4I 5I 6I 7I 8I 9I].zip [*?1..?9, 'I0']),
  *(%w[0V 1V 2V 3V 4V 5V 6V 7V 8V 9V].zip ['V9', *?0..?8]), 
  [' 1', ' 01'], [' 8', ' 98'], [' I', ' '], [' V', ' '],
  # addition, subtraction
  [/ (\d+) (\d+) \+/,                ' \1P \2P '       ], #init addition
  [/ (\d+) (\d+) \-/,                ' \1S \2S '       ], #init subtraction
  [/ ([PS](\d)\w*) (\d+[PS]\w*) /,   ' \2\1 \3 '       ], #sign extend left
  [/ (\d+[PS]\w*) ([PS](\d)\w*) /,   ' \1 \3\2 '       ], #sign extend right
  [/ (\d*)(\d)P(\S*) (\d*)0P(0*) /,  ' \1P\2\3 \4P0\5 '], #advance addition
  [/ (\d*)(\d)S(\S*) (\d*)0S(0*) /,  ' \1S\2\3 \4S0\5 '], #advance subtraction
  [/ (\d+)P(\S*) (\d*[1-5])P(0*) /,  ' \1IP\2 \3VP\4 ' ], #transfer left
  [/ (\d+)P(\S*) (\d*[6-9])P(0*) /,  ' \1VP\2 \3IP\4 ' ], #transfer right
  [/ (\d+)S(\S*) (\d*[1-5])S(0*) /,  ' \1VS\2 \3VS\4 ' ], #decrement both
  [/ (\d+)S(\S*) (\d*[6-9])S(0*) /,  ' \1IS\2 \3IS\4 ' ], #increment both
  [/ [PS](\S+) [PS]0+ /,             ' \1 '            ], #finish 

  # digitwise negation
  *(%w[9N 8N 7N 6N 5N 4N 3N 2N 1N 0N].zip [*'N0'..'N9']),
  #multiplication and division by 2
  *([*'H0'..'H9'].zip %w[0H 0F 1H 1F 2H 2F 3H 3F 4H 4F]),
  *([*'F0'..'F9'].zip %w[5H 5F 6H 6F 7H 7F 8H 8F 9H 9F]),  
  *(%w[0T 1T 2T 3T 4T 5T 6T 7T 8T 9T].zip %w[T0 T2 T4 T6 T8 TI0 TI2 TI4 TI6 TI8]), 
  ['H ', ' '], [' T', ' '],

  # sign correction for */%
  [/ (\d+) (9\d*) ([*\/%])/, ' \1NI \2NI \3'], [' N', ' '],
  # multiplication
  [/ (0+ \d+|\d+ 0+) \*/,     ' 0 '          ], #multiplication by zero
  [/ (\d+) (0\d*[02468]) \*/, ' \1T H\2 *'   ], #multiplication by an even number
  [/ (\d+) (0\d*[13579]) \*/, ' \1 \1 \2V *+'], #multiplication by an odd number
  # division / modulo
  [?/, 'r.'], [?%, 'rs.'],
  [/ (0|9)(\d*) (0\d+) r/,           ' \3 0 \1D\2 '          ], #init division
  [/ (\d+) (\d+) (0\d*)D(\d*) /,     ' \1 \2I \3SD\4 \1S '   ], #subtract divisor
  [/ (\d+) (\d+) (9\d*)D(\d)(\d*) /, ' \1 \2V0 \3P\4D\5 \1P '], #add divisor and advance
  [/ (\d+) (\d+) (9\d*)D /,          ' \2V \3P \1P '         ], #add divisor and finish  

  #exponentiation
  [/ \d+ 0+ \^/,             ' 01 '          ], # case: zeroth power
  [/ 9\d+ 9+ \^/,            ' 9 '           ], # case: reciprocal of negative
  [/ \d+ 9\d+ \^/,           ' 0 '           ], # case: high negative power
  [/ 0\d+ 9\d+ \^/,          ' 0 '           ], # case: reciprocal of positive
  [/ (\d+) 0+1 \^/,          ' \1 '          ], # case: power of one
  [/ (\d+) (\d*[02468]) \^/, ' \1 \1 *H\2 ^' ], # case: even exponent
  [/ (\d+) (\d*[13579]) \^/, ' \1 \2V ^\1 *' ], # case: odd exponent
]                                   

x = gets.tr '^$iv*/+\-^%><dtsz.', ''
until x =~ /^ (\d+ )*$/
  subs.each do |sub|
    x.sub!(*sub) # && (puts x; sleep 0.1)
  end
end

Đối với vòng thưởng, giải pháp ngắn nhất tôi nghĩ ra ( 13 ký tự ) là một giải pháp rõ ràng:

iistisii$<$<$

Dường như với tôi, giải pháp tiền thưởng của bạn bị thiếu ban đầu d(sau đó ii, ngăn xếp chỉ chứa 2, không có gì để trao đổi) và vòng quay cuối cùng (tốt nhất là cái đầu tiên, cái thứ hai chỉ là một hoán đổi trá hình ... ) nên ở bên trái, không phải bên phải.
Mormegil

@Mormegil Tôi đang sử dụng giải thích rằng ngăn xếp tự động mở rộng với số không khi cần. Do đó, không cần phải nhân đôi số 0. Đối với hướng quay, tôi sẽ kiểm tra lại ...
John Dvorak

@Mormegil hướng xoay cố định, cảm ơn.
John Dvorak

Ồ, vâng, tôi đã bỏ lỡ nhận xét về việc diễn giải ngầm, và thật không may giải pháp của tôi không thể làm được điều đó.
Mormegil

11

lắp ráp x86 (trên Win32)

Ở đây có vẻ rất quan trọng, và tất cả chúng ta đều không biết gì về ngôn ngữ lắp ráp trong vấn đề đó. Vì vậy, hãy làm điều đó trong lắp ráp!

Đây là một triển khai ngôn ngữ trong ngôn ngữ lắp ráp x86 (theo cú pháp NASM), với các số được lưu trữ và diễn giải dưới dạng số nguyên 32 bit không dấu, sử dụng trực tiếp ngăn xếp x86. Ngăn xếp ngăn xếp và tràn trong bất kỳ hoạt động số học nào (hoặc chia cho số 0) là lỗi thời gian chạy, chấm dứt chương trình với thông báo lỗi.

        global _start

        extern _GetCommandLineA@0
        extern _GetStdHandle@4
        extern _CreateFileA@28
        extern _GetFileSize@8
        extern _LocalAlloc@8
        extern _ReadFile@20
        extern _CloseHandle@4
        extern _WriteFile@20

section .text

; ---------------------------------------------------------------------------------------
; Initialization
; ---------------------------------------------------------------------------------------

_start:
        ; Retrieve command line
        CALL _GetCommandLineA@0

        ; Skip argv[0]
        MOV ESI, EAX
        XOR EAX, EAX
skipuntilspace:
        MOV AL, [ESI]
        INC ESI
        TEST EAX, EAX
        JE missingparam
        CMP EAX, ' '
        JNE skipuntilspace
        INC ESI

        ; Open the file
        PUSH 0
        PUSH 80h
        PUSH 3
        PUSH 0
        PUSH 1
        PUSH 80000000h
        PUSH ESI
        CALL _CreateFileA@28
        CMP EAX, -1
        JE  cannotopenfile

        ; Get its size
        PUSH EAX
        PUSH 0
        PUSH EAX
        CALL _GetFileSize@8

        PUSH EAX

        ; Allocate memory buffer
        PUSH EAX
        PUSH 0
        CALL _LocalAlloc@8
        TEST EAX, EAX
        MOV ESI, EAX
        JZ outofmemory

        POP ECX
        POP EAX
        PUSH EAX

        ; Store end-of-program pointer
        MOV [programend], ESI
        ADD [programend], ECX

        ; Read the file contents
        PUSH 0
        PUSH buff
        PUSH ECX
        PUSH ESI
        PUSH EAX
        CALL _ReadFile@20
        TEST EAX, EAX
        JZ cannotopenfile

        ; Close the file
        CALL _CloseHandle@4

; ---------------------------------------------------------------------------------------
; Main loop of the interpreter
; ---------------------------------------------------------------------------------------

        ; Store the end of stack into EBP
        MOV EBP, ESP

        ; Push an initial 0 onto the stack
        XOR EAX, EAX
        PUSH EAX

mainloop:
        ; Load the next opcode, if not end of program
        XOR EAX, EAX
        CMP ESI, [programend]
        MOV AL, [ESI]
        JAE endloop
        LEA ESI, [ESI+1]

        ; Check if the opcode is valid
        CMP EAX, (maxop - opcodetable) / 8
        JA  fault_invalidopcode

        ; Check for required stack space
        MOV ECX, [opcodetable + 8 * EAX + 4]
        LEA EDI, [ESP + ECX]
        CMP EDI, EBP
        JA  fault_stackunderflow

        ; Jump to the respective opcode handler
        MOV EAX, [opcodetable + 8 * EAX]
        JMP EAX

; ---------------------------------------------------------------------------------------
; Implementation of the specific operations
; ---------------------------------------------------------------------------------------

        ; ************** CAT 0000 (0): Concatenate (Combine top two numbers in a stack as if they were a string. ex: 12,5 -> 125)
op_concatenate:
        POP EBX
        POP EAX
        MOV ECX, EAX
        MOV EDI, 10
concat_loop:
        XOR EDX, EDX
        SHL EBX, 1
        DIV EDI
        LEA EBX, [4 * EBX + EBX]
        TEST EAX, EAX
        JNZ concat_loop

        ADD EBX, ECX
        PUSH EBX
        JMP mainloop

        ; ************** INC 0001 (1): Increment (Add 1 to the number on the top of the stack)
op_increment:
        POP EAX
        ADD EAX, 1
        PUSH EAX
        JNC mainloop
        JMP fault_intoverflow

        ; ************** DEC 0010 (2): Decrement (Subtract one from the number at the top of the stack)
op_decrement:
        POP EAX
        SUB EAX, 1
        PUSH EAX
        JNC mainloop
        JMP fault_intoverflow

        ; ************** MUL 0011 (3): Multiply (Multiply the top two numbers in the stack)
op_multiply:
        POP EAX
        POP EDX
        MUL EDX
        TEST EDX, EDX
        PUSH EAX
        JZ mainloop
        JMP fault_intoverflow

        ; ************** DIV 0100 (4): Divide (Divide the 2nd-to-top number by the top number on the stack)
op_divide:
        POP ECX
        TEST ECX, ECX
        POP EAX
        JZ fault_dividebyzero
        XOR EDX, EDX
        DIV ECX
        PUSH EAX
        JMP mainloop

        ; ************** MOD 0101 (5): Add (Add the top two numbers on the stack)
op_add:
        POP EAX
        ADD [ESP], EAX
        JNC mainloop
        JMP fault_intoverflow

        ; ************** SUB 0110 (6): Subtract (Subtract the top number on the stack from the one below it)
op_subtract:
        POP EAX
        SUB [ESP], EAX
        JNC mainloop
        JMP fault_intoverflow

        ; ************** EXP 0111 (7): Exponent (Calculate the second-to-top number to the power of the top number)
op_exponent:
        POP ECX
        POP EBX
        MOV EAX, 1
exploop:
        TEST ECX, 1
        JZ expnomult
        MUL EBX
        TEST EDX, EDX
        JNZ fault_intoverflow
expnomult:
        SHR ECX, 1
        JZ expdone
        XCHG EAX, EBX
        MUL EAX
        TEST EDX, EDX
        XCHG EAX, EBX
        JZ exploop
        JMP fault_intoverflow
expdone:
        PUSH EAX
        JMP mainloop

        ; ************** MOD 1000 (8): Modulus: (Find the second-to-top number modulo the top one)
op_modulus:
        POP ECX
        TEST ECX, ECX
        POP EAX
        JZ fault_dividebyzero
        XOR EDX, EDX
        IDIV ECX
        PUSH EDX
        JMP mainloop

        ; ************** ROR 1001 (9): Rotate Right (Shift the stack down one. The number on the bottom is now on the top)
op_rotright:
        MOV EAX, [EBP - 4]
        LEA ECX, [EBP - 4]
        SUB ECX, ESP
        MOV EDX, ESI
        SHR ECX, 2
        LEA EDI, [EBP - 4]
        LEA ESI, [EBP - 8]
        STD
        REP MOVSD
        MOV [ESP], EAX
        CLD
        MOV ESI, EDX
        JMP mainloop

        ; ************** ROL 1010 (A): Rotate Left (Shift the stack up one. The number on the top is now on the bottom)
op_rotleft:
        MOV EAX, [ESP]
        LEA ECX, [EBP - 4]
        SUB ECX, ESP
        MOV EDX, ESI
        SHR ECX, 2
        LEA ESI, [ESP + 4]
        MOV EDI, ESP
        REP MOVSD
        MOV [EBP - 4], EAX
        MOV ESI, EDX
        JMP mainloop

        ; ************** DUP 1011 (B): Duplicate (Copy the top number so that it appears twice. ex: 4,1 becomes 4,1,1)
op_duplicate:
        PUSH DWORD [ESP]
        JMP mainloop

        ; ************** DU2 1100 (C): Double Duplicate (Copy the top two numbers on the stack. ex: 4,1,2 becomes 4,1,2,1,2)
op_dblduplicate:
        PUSH DWORD [ESP+4]
        PUSH DWORD [ESP+4]
        JMP mainloop

        ; ************** SWP 1101 (D): Swap (Swap the top two numbers on the stack. ex: 4,1,2 becomes 4,2,1)
op_swap:
        POP EAX
        POP EDX
        PUSH EAX
        PUSH EDX
        JMP mainloop

        ; ************** SW2 1110 (E): Double Swap (Swap the top two numbers with two below them.ex: 1,2,3,4,5 becomes 1,4,5,2,3)
op_dblswap:
        POP EAX
        POP EBX
        POP ECX
        POP EDX
        PUSH EBX
        PUSH EAX
        PUSH EDX
        PUSH ECX
        JMP mainloop

        ; ************** POP 1111 (F): Delete/Pop (Remove the number at the top of the stack)
op_pop:
        POP EAX
        JMP mainloop


; ---------------------------------------------------------------------------------------
; End of the program: print out the resulting stack and exit
; ---------------------------------------------------------------------------------------

endloop:
        MOV ESI, ESP

printloop:
        CMP ESI, EBP
        JNB exit
        MOV EAX, [ESI]
        MOV EBX, ESI
        PUSH EBX
        CALL printnum
        POP EBX
        LEA ESI, [EBX + 4]
        JMP printloop

exit:
        MOV ESP, EBP
        ;POP EAX
        XOR EAX, EAX
        RET


; ---------------------------------------------------------------------------------------
; Faults
; ---------------------------------------------------------------------------------------

fault_invalidopcode:
        MOV EAX, err_invalidopcode
        JMP fault

fault_stackunderflow:
        MOV EAX, err_stackunderflow
        JMP fault

fault_dividebyzero:
        MOV EAX, err_dividebyzero
        JMP fault

fault_intoverflow:
        MOV EAX, err_intoverflow
        JMP fault

fault:
        CALL print
        MOV EAX, crlf
        CALL print

        MOV ESP, EBP
        MOV EAX, 1
        RET


missingparam:
        MOV EAX, err_missingparameter
        JMP fault

cannotopenfile:
        MOV EAX, err_cannotopenfile
        JMP fault

outofmemory:
        MOV EAX, err_outofmemory
        JMP fault

; ---------------------------------------------------------------------------------------
; Helper functions
; ---------------------------------------------------------------------------------------

printnum:
        MOV EBX, 10
        CALL printnumrec
        MOV EAX, crlf
        JMP print

printnumrec:
        PUSH EAX
        PUSH EDX
        XOR EDX, EDX
        DIV EBX
        TEST EAX, EAX
        JZ printnumend
        CALL printnumrec
printnumend:
        MOV EAX, EDX
        CALL printdigit
        POP EDX
        POP EAX
        RET


printdigit:
        ADD EAX, '0'
        MOV [printbuff], EAX
        MOV EAX, printbuff
        JMP print


print:
        MOV  ESI, EAX
        PUSH 0
        PUSH buff
        CALL strlen
        PUSH EAX
        PUSH ESI
        PUSH -11
        CALL _GetStdHandle@4
        PUSH EAX
        CALL _WriteFile@20
        RET

strlen:
        XOR ECX, ECX
strlen_loop:
        CMP BYTE [ESI+ECX], 0
        JE strlen_end
        LEA ECX, [ECX+1]
        JMP strlen_loop
strlen_end:
        MOV EAX, ECX
        RET


; ---------------------------------------------------------------------------------------
; Data
; ---------------------------------------------------------------------------------------

section .data

; Table of opcode handlers and required stack space (in bytes, i.e. 4*operands)
opcodetable:
        DD op_concatenate, 8
        DD op_increment, 4
        DD op_decrement, 4
        DD op_multiply, 8
        DD op_divide, 8
        DD op_add, 8
        DD op_subtract, 8
        DD op_exponent, 8
        DD op_modulus, 8
        DD op_rotright, 0
        DD op_rotleft, 0
        DD op_duplicate, 4
        DD op_dblduplicate, 8
        DD op_swap, 8
        DD op_dblswap, 16
        DD op_pop, 4
maxop:

crlf                    DB 13, 10, 0
err_invalidopcode       DB "Invalid opcode", 0
err_stackunderflow      DB "Stack underflow", 0
err_dividebyzero        DB "Division by zero", 0
err_intoverflow         DB "Integer overflow", 0

err_missingparameter:   DB "Missing parameter: Use nexlang file.bin", 0
err_cannotopenfile:     DB "Unable to open input file", 0
err_outofmemory:        DB "Not enough memory", 0

section .bss

programend      RESD 1
printbuff       RESD 1
buff            RESD 1

Để biên dịch cái này, sử dụng cái gì đó như

nasm.exe -fwin32 nexlang.asm
ld -o nexlang.exe -e _start nexlang.obj -s -lkernel32

Chương trình nhận được tên của tệp nhị phân chứa chương trình trên dòng lệnh (ví dụ nexlang.exe testprg.bin). Khi hoàn thành, nó sẽ in các nội dung cuối cùng của ngăn xếp thành đầu ra tiêu chuẩn ở định dạng có thể đọc được.

Để giúp kiểm tra, lưu các mục sau vào nex.def:

%define CAT DB 00h
%define INC DB 01h
%define DEC DB 02h
%define MUL DB 03h
%define DIV DB 04h
%define ADD DB 05h
%define SUB DB 06h
%define EXP DB 07h
%define MOD DB 08h
%define ROR DB 09h
%define ROL DB 0Ah
%define DUP DB 0Bh
%define DU2 DB 0Ch
%define SWP DB 0Dh
%define SW2 DB 0Eh
%define POP DB 0Fh

Và sau đó viết các chương trình NEX (không tồn tại của bạn, như được đặt tên trong tiêu đề câu hỏi) bằng cách sử dụng các ký hiệu được xác định ở trên và biên dịch với một cái gì đó như

nasm.exe -p nex.def -o prg.bin prg.nex

Ví dụ: đối với trường hợp thử nghiệm ban đầu, sử dụng như sau prg.nex:

INC     ; 1
INC     ; 2
INC     ; 3
INC     ; 4
DUP     ; 4 4
DU2     ; 4 4 4 4
ADD     ; 8 4 4
DU2     ; 8 4 8 4 4
ADD     ; 12 8 4 4
DUP     ; 12 12 8 4 4
ROR     ; 4 12 12 8 4
ADD     ; 16 12 8 4

Và cuối cùng, đối với thử thách của 2014 2014, sử dụng chương trình NEX 14 byte sau đây:

DUP     ; 0 0
DUP     ; 0 0 0
INC     ; 1 0 0
INC     ; 2 0 0
SWP     ; 0 2 0
CAT     ; 20 0
SWP     ; 0 20
INC     ; 1 20
DUP     ; 1 1 20
INC     ; 2 1 20
INC     ; 3 1 20
INC     ; 4 1 20
CAT     ; 14 20
CAT     ; 2014

Tại sao LEA ESI, [ESI+1]chứ không phải INC ESI?
Điểm_Under

Trên thực tế, trong kết quả cuối cùng, không có lý do thực sự; nói chung, tốc độ / kích thước / cờ bị ảnh hưởng có thể quan trọng. Nhưng tôi đã không thực sự tối ưu hóa kết quả, về cơ bản nó chỉ là một nỗ lực đầu tiên.
Mormegil

1
Điều này chắc chắn là tuyệt nhất. Tôi đã có rất nhiều niềm vui chơi xung quanh nó :).
Tacovy

9

GolfScript, 64 ký tự

OK, vì vậy tôi quyết định thử và chơi golf này. Và ngôn ngữ nào tốt hơn để chơi golf hơn GolfScript?

Thuận tiện, bản thân GolfScript đã là một ngôn ngữ dựa trên ngăn xếp với các lệnh một byte và, như đã xảy ra, 11 trong số 16 lệnh của bạn ánh xạ trực tiếp tới các lệnh GolfScript tích hợp. Vì vậy, tất cả những gì tôi thực sự cần làm để diễn giải ngôn ngữ của bạn là triển khai năm lệnh còn lại trong GolfScript và xây dựng bảng dịch:

0\{'`+~
)
(
*
/
+
-
?
%
](+~
])\~
.
1$1$
\
[@]\+~\
;'n%=~}/]-1%`

Mã này có vẻ như trải rộng, bởi vì tôi đang sử dụng các dòng mới làm dấu phân cách cho bảng dịch. Ban đầu 0\đẩy một số không vào ngăn xếp và di chuyển nó bên dưới chương trình đầu vào. Các { }/vòng lặp, bao gồm hầu hết các mã, có chương trình đầu vào ra khỏi stack và lặp thân vòng lặp hơn so với từng nhân vật của mình, và trận chung kết ]-1%`thu thập những ngăn xếp vào một mảng, đảo ngược nó (vì bắt đầu sản xuất mẫu của bạn từ phía trên cùng của ngăn xếp) và xâu chuỗi nó.

Phần thân vòng lặp bắt đầu bằng một chuỗi trích dẫn đơn 16 dòng. n%chia chuỗi này khi ngắt dòng, =tra cứu chuỗi con tương ứng với ký tự đầu vào và ~đánh giá chuỗi con dưới dạng mã GolfScript.

Cuối cùng, đây là các triển khai GolfScript của 16 lệnh:

  • 0 = `+~: nối hai số dưới dạng chuỗi
  • 1 = ): gia tăng
  • 2 = (: giảm
  • 3 = *: nhân lên
  • 4 = /: chia
  • 5 = +: thêm
  • 6 = -: trừ
  • 7 = ?: nâng cao sức mạnh
  • 8 = %: mô đun
  • 9 = ](+~: xoay chồng phải
  • A = ])\~: xoay ngăn xếp trái
  • B = .: trùng lặp
  • C = 1$1$: nhân đôi
  • D = \: hoán đổi
  • E = [@]\+~\: hoán đổi kép
  • F = ;: pop

Tôi không hài lòng với trao đổi kép - nó xấu và dài hơn bất kỳ lệnh nào khác. Cảm giác như phải có một cách tốt hơn, nhưng nếu vậy, tôi vẫn chưa tìm thấy nó. Tuy nhiên, ít nhất nó hoạt động.

Ví dụ: chạy chương trình trên trên đầu vào (được cung cấp dưới dạng chuỗi trích dẫn hai lần GolfScript / Ruby / Perl / Python / v.v.):

"\x01\x01\x0B\x0C\x05\x0C\x05\x0B\x09\x05"

mang lại sản lượng:

[8 6 4 2]

Chỉnh sửa: Tôi đã quản lý để lưu thêm hai ký tự, với tổng số 62 ký tự , sử dụng bảng mã nhỏ gọn hơn của bảng dịch. Tuy nhiên, đó là loại hy sinh dễ đọc:

0\{(')(*/+-?%'1/'](+~
])\~
.
1$1$
\
[@]\+~\
;
`+~'n/+=~}/]-1%`

Các tính năng đáng chú ý của phiên bản này bao gồm (ở đầu vòng lặp, dịch chuyển các chỉ số lệnh từ 0..15 đến -1..14 để tôi có thể đặt chuỗi dài các lệnh đơn ký tự từ 1 đến 8 ở đầu của cái bàn. Điều này cho phép tôi lưu trữ chúng trong một chuỗi riêng biệt và loại bỏ tám dòng mới phân định chúng; than ôi, sự phức tạp thêm chi phí cho tôi sáu nhân vật ở nơi khác.


Bạn có thể ghé +vào])\+~
John Dvorak

@JanDvorak: Ah, vâng, điều đó đã quá rõ ràng. Cảm ơn!
Ilmari Karonen

8

Haskell

Để cho vui, tôi đã thực hiện một giải pháp không sử dụng biến nào, chỉ kết hợp các chức năng với nhau.

import Control.Applicative
import Control.Monad
import Control.Monad.State
import Data.Function

type SM = State [Int]

pop :: SM Int
pop = state ((,) <$> head <*> tail)

push :: Int -> SM ()
push = modify . (:)

popN :: Int -> SM [Int]
popN = sequence . flip replicate pop

pushN :: [Int] -> SM ()
pushN = mapM_ push

rotL, rotR :: Int -> [a] -> [a]
rotL = (uncurry (flip (++)) .) . splitAt
rotR = (reverse .) . flip (flip rotL . reverse)

step :: Int -> SM ()
step 0x00 = push =<< ((read .) . on (++) show) <$> pop <*> pop
step 0x01 = push . (+ 1) =<< pop
step 0x02 = push . subtract 1 =<< pop
step 0x03 = push =<< (*) <$> pop <*> pop
step 0x04 = push =<< flip div <$> pop <*> pop
step 0x05 = push =<< (+) <$> pop <*> pop
step 0x06 = push =<< flip (-) <$> pop <*> pop
step 0x07 = push =<< flip (^) <$> pop <*> pop
step 0x08 = push =<< flip mod <$> pop <*> pop
step 0x09 = modify $ (:) <$> last <*> init
step 0x0A = modify $ rotL 1
step 0x0B = pop >>= pushN . replicate 2
step 0x0C = popN 2 >>= pushN . concat . replicate 2
step 0x0D = popN 2 >>= pushN . rotL 1
step 0x0E = popN 4 >>= pushN . rotL 2
step 0x0F = void pop

run :: [Int] -> [Int]
run = flip execState [0] . mapM_ step

6

Ruby, 330 316 ký tự

Tôi quyết định đánh golf nó. (Bởi vì điều đó luôn vui vẻ.)

s=[0]
o=->c{t=s.pop;s.push s.pop.send(c,t)}
gets.chop.each_char{|c|eval %w[t=s.pop;s.push"#{s.pop}#{t}".to_i s[-1]+=1 s[-1]-=1 o[:*] o[:/] o[:+] o[:-] o[:**] o[:%] s.rotate! s.rotate!(-1) s.push(s[-1]) s.concat(s[-2..-1]) s[-1],s[-2]=s[-2],s[-1] s[-1],s[-2],s[-3],s[-4]=s[-4],s[-3],s[-1],s[-2] s.pop][c.to_i 16]}
p s

Phần chính là đây:

gets.chop.each_char{|c|eval [(huge array of strings)][c.to_i 16]}

Nó dịch mỗi chữ số hex thành một số nguyên cơ số 10, sau đó sử dụng chuỗi [(huge array of strings)]để tìm đúng chuỗi đại diện cho lệnh đó. Sau đó, đó evallà chuỗi đó.

Lưu ý rằng %w[x y z]tương đương với ['x','y','z'].

Tôi cũng thích làm thế nào bạn có thể tìm thấy khuôn mặt cười trong dòng đó! Một số trong số họ là

  • :*
  • :/
  • :-]
  • :%

Chạy mẫu:

c:\a\ruby>random_cg_lang
11BC5C5B95
[2, 4, 6, 8]

4

C - 642 634 ký tự

Chỉ dành cho $iv*/+-^%><dtsz.phương ngữ (thêm qdưới dạng ký tự kết thúc, cùng với 0):

#define P s=*t;a=realloc(a,--w<<2);t=a+w-1;
#define H(n)a=realloc(a,(w+=n)<<2);
#define B(n)break;case n:
*a,*t,s,w=1,i;main(){t=a=calloc(4,1);while((i=getchar())&&i^'q')switch(i){B(36)P*t*=pow(10,((
int)log10(s))+1);*t+=s;B(105)++*t;B(118)--*t;B(42)P*t*=s;B(47)P*t/=s;B(43)P*t+=s;B(45)P*t-=s;
B(94)P*t=pow(*t,s);B(37)P*t%=s;B(62)s=*a;memcpy(a,a+1,(w-1)<<2);*t=s;B(60)s=*t;memcpy(a+1,a,(
w-1)<<2);*a=s;B(100)H(1)t=a+w-2;s=*t;t++;*t=s;B(116)H(2)t=a+w-1;t[-1]=t[-3];*t=t[-2];B(115)s=
*t;*t=t[-1];t[-1]=s;B(122)s=*t;*t=t[-2];t[-2]=s;s=t[-1];t[-1]=t[-3];t[-3]=s;B(46)P}putchar('[
');putchar(32);while(w)printf("%i ",a[--w]);putchar(']');}

Giải pháp cho thử thách 2014 : dididiizs>.


Tôi nghĩ bạn có thể thua free(a);. Và, không nên <<2trong các realloccuộc gọi?
kẻ lừa đảo người lái xe

@luserdroog Đúng, cảm ơn. Tôi chỉ quen với free()bộ nhớ: P
Oberon

3

k, 228

(,0){({(-7h$,/$2#x),2_x};@[;0;+;1];@[;0;-;1];{.[*;|2#x],2_x};{.[%;|2#x],2_x};
{.[+;|2#x],2_x};{.[-;|2#x],2_x};{.[xexp;|2#x],2_x};{.[mod;|2#x],2_x};{(*|x),-1_x};
{(1_x),*x};{(*x),x};{(2#x),x};{(|2#x),2_x};{,/(|2 2#x),4_x};1_)[y]x}/
0x01010b0c050c050b0905

8 4 6 2

Có một số lượng lặp lại hợp lý trong việc thực hiện các hướng dẫn tương tự, có thể được thiết kế ở một mức độ nào đó.


Tôi tiếp tục tìm thấy điều tương tự là đúng với tôi.
kẻ lừa đảo người lái xe

3

C 924 882 622 603 587 569 562 ký tự

Với các dòng mới rõ ràng bị loại bỏ (giữ lại để dễ đọc).

#define A sbrk(8);signal(11,S);
#define W(x)write(1,x,1);
#define P (t>s?*--t:0)
#define U *t++
#define B(x,y)else if(b==(w=w+1 x)){w=P;y;U=w;}
*t,*s,w,a,d;char b;S(x){A}
p(x){if(x<0){W("-")x=-x;}if(x>9)p(x/10);b=48+x%10;W(&b)}
main(c){t=s=A U=0;
while(read(0,&b,1))if(!(w=47));
B(,w+=P*pow(10,w?ceil(log10(w)):1))
B(,++w)
B(,--w)
B(,w*=P)
B(,w=P/w)
B(,w+=P)
B(,w=P-w)
B(,w=pow(P,w))
B(,w=P%w)
B(,w=*s;memmove(s,s+1,t-s<<2))
B(+7,memmove(s+1,s,t++-s<<2);*s=w;w=P)
B(,U=w)
B(,a=P;U=a;U=w;U=a)
B(,a=P;U=w;w=a)
B(,a=P;c=P;d=P;U=a;U=w;U=c;w=d)
B(,w=P)
for(W("[")t>s;)p(P),W(" ")
W("]")}

Điều này thực hiện cách giải thích "dòng chảy đẩy không" từ nhận xét của Jan Dvorak.

Phiên bản chơi gôn thực sự đã thay đổi đáng kể so với phiên bản không có người ở đây, dưới áp lực (hoan nghênh) của câu trả lời tốt của Oberon .

Tôi thấy rằng việc thay thế switchtuyên bố có lợi cho if... elsechuỗi cho phép tôi loại bỏ tất cả các chữ số từ các trường hợp của tôi . Thay vào đó, nó khởi tạo wbiến thành 47, do đó, một mức tăng sẽ tăng lên 48 (== ascii '0') sau đó mỗi trường hợp tăng wcho đến khi chúng ta cần bỏ qua 'A'điểm mà chúng ta sử dụng đối số macro đầu tiên trống rỗng, có thêm 7 để tăng thêm đến 'A'. Phiên bản không được hiển thị sẽ hiển thị yêu thích sbrk/ SIGSEGVmẹo của tôi để có được bộ nhớ "miễn phí" mà không cần phân bổ thêm.

#include<math.h>
#include<signal.h>
void S(int x){signal(SIGSEGV,S);sbrk(8*8*8);}
int*s,*t,*i,w,a,c,d;    //stack top index working accumulator count data
u(x){*t++=x;}           //push()
o(){return t>s?*--t:0;} //pop()
#define W(x)write(1,&x,1);  //output a byte
p(x){                   //print()
    if(x<0){    //negative?
        W(*"-") //output '-'
        x=-x;   //negate
    }
    if(x>9)     //more than one digit?
        p(x/10); //recurse after integer-divide
    b=48+x%10;   //isolate and convert single digit to ascii
    W(b)         //output ascii digit
}
main(){
    char b[1];
    signal(SIGSEGV,S);  //auto-allocate memory for stack
    t=s=sbrk(8*8*8);  //get start of memory and allocate
    while(read(0,b,1)){
        write(1,b,1); //for debugging: echo the command being executed
        switch(*b){
            case '0': w=o(); a=o(); for(c=ceil(log10(w));c>0;c--) a*=10; u(a+w); break;
            case '1': u(o()+1); break;
            case '2': u(o()-1); break;
            case '3': w=o(); u(o()*w); break;
            case '4': w=o(); u(o()/w); break;
            case '5': u(o()+o()); break;
            case '6': w=o(); u(o()-w); break;
            case '7': c=o();a=1; for(w=o();c>0;c--) a*=w; u(a); break;
            case '8': w=o(); u(o()%w); break;
            case '9': w=*s; memmove(s,s+1,4*(t-s-1)); t[-1]=w; break;
            case 'A': w=t[-1]; memmove(s+1,s,4*(t-s-1)); *s=w; break;
            case 'B': w=o(); u(w); u(w); break;
            case 'C': w=o(); a=o(); u(a); u(w); u(a); u(w); break;
            case 'D': w=o(); a=o(); u(w); u(a); break;
            case 'E': w=o(); a=o(); c=o(); d=o(); u(a); u(w); u(d); u(c); break;
            case 'F': o(); break;
        }
    }
    write(1,"\n[",2);   //dump the stack
    i=t;
    do {
        p(*--i);
    } while(i>s && write(1,",",1));
    write(1,"]\n",2);
}

tào lao Tôi đã không xem xét tiêu cực trong việc nối. Tôi nghĩ logthậm chí không được xác định.
kẻ lừa đảo người lái xe

Phiên bản được chơi gôn sẽ có tốc độ chậm lớn khi chạm vào ranh giới trang, nó sẽ phân tách liên tục, phân bổ 8 byte trong trình xử lý, thử lại quyền truy cập bộ nhớ, lặp lại lần nữa, lặp đi lặp lại cho mỗi nhịp 8 byte cho đến khi bộ nhớ trở nên hợp lệ. Người không có kinh nghiệm sử dụng hằng số lớn hơn và không nên chậm như vậy, nhưng thuật toán là như nhau.
kẻ lừa đảo người lái xe

1

R, 428 ký tự

f=function(I){s=0;for(i in strsplit(I,"")[[1]]){r=s[-(1:2)];s=switch(i,'0'=c(as.integer(paste0(s[2],s[1])),r),'1'=c(s[1]+1,s[-1]),'2'=c(s[1]-1,s[-1]),'3'=c(s[1]*s[2],r),'4'=c(s[2]%/%s[1],r),'5'=c(s[1]+s[2],r),'6'=c(s[1]-s[2],r),'7'=c(s[2]^s[1],r),'8'=c(s[2]%%s[1],r),'9'=c(s[length(s)],s[-length(s)]),'A'=c(s[-1],s[1]),'B'=c(rep(s[1],2),s[-1]),'C'=c(rep(s[1:2],2),r),'D'=c(s[2:1],r),'E'=c(s[3:4],s[1:2],s[-(1:4)]),'F'=s[-1])};s}

Với vết lõm:

f=function(I){
    s=0
    for(i in strsplit(I,"")[[1]]){
        r=s[-(1:2)]
        s=switch(i,
                '0'=c(as.integer(paste0(s[2],s[1])),r),
                '1'=c(s[1]+1,s[-1]),
                '2'=c(s[1]-1,s[-1]),
                '3'=c(s[1]*s[2],r),
                '4'=c(s[2]%/%s[1],r),
                '5'=c(s[1]+s[2],r),
                '6'=c(s[1]-s[2],r),
                '7'=c(s[2]^s[1],r),
                '8'=c(s[2]%%s[1],r),
                '9'=c(s[length(s)],s[-length(s)]),
                'A'=c(s[-1],s[1]),
                'B'=c(rep(s[1],2),s[-1]),
                'C'=c(rep(s[1:2],2),r),
                'D'=c(s[2:1],r),
                'E'=c(s[3:4],s[1:2],s[-(1:4)]),
                'F'=s[-1])
        }
    s
    }

Trong hành động:

> f('11BC5C5B95')
[1] 8 6 4 2

1

JavaScript, 685

Phiên bản không chơi gôn ( ý chính ):

var Token = {
  Concatenate: '0',
  Increment: '1',
  Decrement: '2',
  Multiply: '3',
  Divide: '4',
  Add: '5',
  Subtract: '6',
  Exponent: '7',
  Modulus: '8',
  RotateRight: '9',
  RotateLeft: 'A',
  Duplicate: 'B',
  DoubleDuplicate: 'C',
  Swap: 'D',
  DoubleSwap: 'E',
  Delete: 'F'
};

function parse(input, mem) {
  var a, b, c, d;
  var stack = mem ? mem.slice() : [0];
  for (var i = 0, n = input.length; i < n; i++) {
    switch (input[i]) {
      case Token.Concatenate:
        a = stack.pop();
        b = stack.pop();
        stack.push(parseInt([b] + a));
        break;

      case Token.Increment:
        a = stack.pop();
        stack.push(a + 1);
        break;

      case Token.Decrement:
        a = stack.pop();
        stack.push(a - 1);
        break;

      case Token.Multiply:
        a = stack.pop();
        b = stack.pop();
        stack.push(b * a);
        break;

      case Token.Divide:
        a = stack.pop();
        b = stack.pop();
        stack.push(b / a | 0);
        break;

      case Token.Add:
        a = stack.pop();
        b = stack.pop();
        stack.push(b + a);
        break;

      case Token.Subtract:
        a = stack.pop();
        b = stack.pop();
        stack.push(b - a);
        break;

      case Token.Exponent:
        a = stack.pop();
        b = stack.pop();
        stack.push(Math.pow(b, a));
        break;

      case Token.Modulus:
        a = stack.pop();
        b = stack.pop();
        stack.push(b % a);
        break;

      case Token.RotateRight:
        a = stack.shift();
        stack.push(a);
        break;

      case Token.RotateLeft:
        a = stack.pop();
        stack.unshift(a);
        break;

      case Token.Duplicate:
        a = stack[stack.length - 1];
        stack.push(a);
        break;

      case Token.DoubleDuplicate:
        a = stack[stack.length - 1];
        b = stack[stack.length - 2];
        stack.push(b, a);
        break;

      case Token.Swap:
        a = stack.pop();
        b = stack.pop();
        stack.push(a, b);
        break;

      case Token.DoubleSwap:
        a = stack.pop();
        b = stack.pop();
        c = stack.pop();
        d = stack.pop();
        stack.push(b, a, d, c);
        break;

      case Token.Delete:
        stack.pop();
        break;

      default:
        throw new SynxtaxError('Invalid token "' + input[i] + '"');
    }
  }

  return stack.reverse();
}

exports.Token = Token;
exports.parse = parse;

Phiên bản chơi gôn:

function f(c){var b,d,e,f,a=[i=0],g=c.length;a.a=a.pop;for(a.b=a.push;i<g;i++)switch(c[i])
{case"0":b=a.a();a.b(parseInt([a.a()]+b));break;case"1":a[a.length-1]++;break;case"2":
a[a.length-1]--;break;case"3":a.b(a.a()*a.a());break;case"4":b=a.a();a.b(a.a()/b|0);break;
case"5":a.b(a.a()+a.a());break;case"6":b=a.a();a.b(a.a()-b);break;case"7":b=a.a();
a.b(Math.pow(a.a(),b));break;case"8":b=a.a();a.b(a.a()%b);break;case"9":a.b(a.shift());break;
case"A":a.a();a.unshift(a.a());break;case"B":a.b(a[a.length-1]);break;case"C":
a.b(a[a.length-2],a[a.length-1]);break;case"D":b=a.a();a.b(b,a.a());break;case"E":b=a.a();
d=a.a();e=a.a();f=a.a();a.b(d,b,f,e);break;case"F":a.a()}return a.reverse()}

Thí dụ:

> f('11BC5C5B95')
[ 8, 6, 4, 2]

1

Haskell

import Data.List (elemIndex)

type Stack = [Integer]

u :: (Integer -> Integer) -> Stack -> Stack
u p (x:t) = p x : t -- unary operation

b :: (Integer -> Integer -> Integer) -> Stack -> Stack
b p (x:y:t) = p x y : t -- binary operation

encoding :: String
encoding = "$iv*/+-^%><dtsz."
-- encoding = "0123456789ABCDEF"

-- list of operations
ops :: [Stack -> Stack]
ops = [
 b (\x y -> read (show x ++ show y)),-- concatenation
 u (+1), -- increment
 u (subtract 1), -- decrement
 b (*), -- multiplication
 b div, -- division
 b (+), -- addition
 b (-), -- subtraction
 b (^), -- exponent
 b mod, -- modulus
 (\s -> last s : init s), -- rotate right
 (\(x:t) -> t ++ [x]), -- rotate left
 (\(x:t) -> x:x:t), -- duplicate
 (\(x:y:t) -> x:y:x:y:t), -- double duplicate
 (\(x:y:t) -> y:x:t), -- swap
 (\(x:y:x':y':t) -> x':y':x:y:t), -- double swap
 tail] -- pop

run :: String -> Maybe Stack
run code = run' code [0] where
  run' [] stack = Just stack
  run' (x:t) stack = elemIndex x encoding >>= run' t . ($stack) . (ops!!)

Đang chạy

λ: run "diidt^svz"
Just [2,0,1,4]

"Đối với thử thách năm 2014 rõ ràng là không thể vì chúng tôi chỉ có thể nhận được các bản sao số 0 trong ngăn xếp với các thao tác AF" - WAT? Tăng số không tạo ra ... một số khác, phải không?
John Dvorak

@JanDvorak Nhưng chúng ta cần viết '1' để tăng, chữ số bị cấm, phải không?
swish

Đó là bi kịch của sự lựa chọn mã hóa đó. Nếu bạn ánh xạ tập hợp dấu chấm câu (có thể bằng tr?) Thì nó có thể trở thành có thể.
luser droog

1

Lisp thường gặp - 589

Chấp nhận đầu vào hex không có khoảng trắng.

(setf w'(0))(defmacro u(&rest b)`(let((a(pop w))(b(pop w))),@b))(defmacro v(s)`(u(push(funcall ,s b a)w)))(setf i(list'(u(push(parse-integer(append(write-to-string b)(write-to-string a)))w))'(incf(car w))'(decf(car w))'(v #'*)'(v #'/)'(v #'+)'(v #'-)'(v #'expt)'(v #'%)'(let((a (car(last w))))(nbutlast w)(push a w))'(let((a(pop w)))(nconc w(list a)))'(push(car w)w)'(progn(push(cadr w)w)(push(cadr w)w))'(u(push a w)(push b w))'(u(push a(cdr(nthcdr 2 w)))(push b(cdr(nthcdr 2 w))))'(pop w)))(mapcar(coerce(read-line)'list)(lambda(a)(eval(nth(parse-integer(string a):radix 16)i)))(print w)

Ung dung:

(defparameter *stack* '(0))

(defmacro topvalues (&rest body)
    `(let ((top1 (pop *stack*))
           (top2 (pop *stack*))) ,@body))

(defmacro simple-op (opsym &rest body)
    `(topvalues 
        (push (funcall ,opsym top2 top1) *stack* )))

(defparameter *ops*
    (list
        ;concatenate
        '(topvalues
            (push 
                (parse-integer (append (write-to-string b) (write-to-string a)))
                *stack*))

        ;increment
        '(incf (first *stack*)) 

        ;decrement
        '(decf (first *stack*)) 

        ;multiply
        '(simple-op #'*)

        ;divide
        '(simple-op #'/)

        ;add
        '(simple-op #'+)

        ;subtract 
        '(simple-op #'-)

        ;exponent
        '(simple-op #'expt)

        ;modulus
        '(simple-op #'%)

        ;rotate right
        '(let ((a (car (last *stack*))))
            (nbutlast *stack*)
            (push a *stack*))

        ;rotate left
        '(let ((a (pop *stack*)))
            (nconc *stack* (list a)))

        ;duplicate
        '(push (first *stack*) *stack*)

        ;double duplicate
        '(progn 
            (push (second *stack*) *stack*)
            (push (second *stack*) *stack*))

        ;swap
        '(topvalues
            (push top1 *stack*)
            (push top2 *stack*))

        ;double swap
        '(topvalues 
            (push top1 (cdr (nthcdr 2 *stack*)))
            (push top2 (cdr (nthcdr 2 *stack*))))

        ;delete/pop
        '(pop *stack*)))

(mapcar 
(lambda (a)
    (eval (nth (parse-integer (string a) :radix 16) *ops*)))
(coerce (read-line) 'list))

1

PHP

nó không phải là đẹp nhất, nhưng nó hoạt động.

chạy từ shell, mong đợi một tên tệp là đối số đầu tiên. nó chấp nhận bất kỳ phương ngữ nào trong số 3 phương ngữ (thậm chí hỗn hợp)

hành vi không được xác định cho tiêu cực hoặc chỉ số bị thiếu

<?php
$f[0] = $f[48] = $f[36] = function(&$s){$v=array_shift($s);$s[0] .= $v;};
$f[1] = $f[49] = $f[105] = function(&$s){$s[0]++;};
$f[2] = $f[50] = $f[118] = function(&$s){$s[0]--;};
$f[3] = $f[51] = $f[42] = function(&$s){$v = array_shift($s); $s[0] *= $v;};
$f[4] = $f[52] = $f[47] = function(&$s){$v = array_shift($s); $s[0] = intval(floor($s[0] / $v));};
$f[5] = $f[53] = $f[43] = function(&$s){$v = array_shift($s); $s[0] += $v;};
$f[6] = $f[54] = $f[45] = function(&$s){$v = array_shift($s); $s[0] -= $v;};
$f[7] = $f[55] = $f[94] = function(&$s){$v = array_shift($s); $s[0] = pow($s[0], $v);};
$f[8] = $f[56] = $f[37] = function(&$s){$v = array_shift($s); $s[0] %= $v;};
$f[9] = $f[57] = $f[62] = function(&$s){$v = array_pop($s); array_unshift($s, $v);};
$f[10] = $f[65] = $f[60] = function(&$s){$v = array_shift($s); array_push($s, $v);};
$f[11] = $f[66] = $f[100] = function(&$s){array_unshift($s, $s[0]);};
$f[12] = $f[67] = $f[116] = function(&$s){$v = [$s[0], $s[1]]; array_unshift($s, $v[0], $v[1]);};
$f[13] = $f[68] = $f[115] = function(&$s){$v = $s[0]; $s[0] = $s[1]; $s[1] = $v;};
$f[14] = $f[69] = $f[122] = function(&$s){$v = $s[0]; $s[0] = $s[2]; $s[2] = $v; $v = $s[1]; $s[1] = $s[3]; $s[3] = $v;};
$f[15] = $f[70] = $f[46] = function(&$s){array_unshift($s);};

$stack = [0];
$file = fopen($argv[1], 'rb');
$size = filesize($argv[1]);
while($size--){
    $f[ord(fread($file, 1))]($stack);
}
fclose($file);
echo '['.implode(',',$stack)."]\n";

1

PureBasic - 2821 891 ký tự

Đây là một trình thông dịch tương tác - không có tệp, bạn chỉ cần nhập các mã được cung cấp 0-9, AF và nó sẽ thực thi lệnh đó và hiển thị như bài viết ví dụ hiển thị nó.

Sử dụng "X" hoặc "Q" để thoát.

Điều này thực sự thú vị để làm :)

Global NewList ProgramStack.q()
Global Num1.q, Num2.q

Macro Push(Value)
  LastElement(ProgramStack())
  AddElement(ProgramStack())
  ProgramStack() = Value
EndMacro

Macro Pop(Variable)
  LastElement(ProgramStack())
  Variable = ProgramStack()
  DeleteElement(ProgramStack())
EndMacro

Macro Peek(Variable)
  LastElement(ProgramStack())
  Variable = ProgramStack()
EndMacro

Push(0)

Procedure Concatenate()
  Pop(Num1)
  Pop(Num2)

  Push(Val( Str(Num2) + Str(Num1) ))
EndProcedure

Procedure Increment()
  LastElement(ProgramStack())
  ProgramStack() + 1
EndProcedure

Procedure Decrement()
  LastElement(ProgramStack())
  ProgramStack() - 1
EndProcedure

Procedure Multiply()
  Pop(Num1)
  Pop(Num2)

  Push( Num2 * Num1 )
EndProcedure

Procedure Divide()
  Pop(Num1)
  Pop(Num2)

  Push( Num2 / Num1 )
EndProcedure

Procedure Add()
  Pop(Num1)
  Pop(Num2)

  Push( Num2 + Num1 )
EndProcedure

Procedure Subtract()
  Pop(Num1)
  Pop(Num2)

  Push( Num2 - Num1 )
EndProcedure

Procedure Exponent()
  Pop(Num1)
  Pop(Num2)

  Push( Pow(Num2, Num1) )
EndProcedure

Procedure Modulus()
  Pop(Num1)
  Pop(Num2)

  Push( Mod(Num2, Num1) )
EndProcedure

Procedure RotateRight()
  FirstElement(ProgramStack())
  Num1 = ProgramStack()
  DeleteElement(ProgramStack(),1)
  Push(Num1)
EndProcedure

Procedure RotateLeft()
  Pop(Num1)
  FirstElement(ProgramStack())
  InsertElement(ProgramStack())
  ProgramStack() = Num1
EndProcedure

Procedure Duplicate()
  Peek(Num1)
  Push(Num1)
EndProcedure

Procedure DoubleDuplicate()
  Pop(Num1)
  Pop(Num2)
  Push(Num2)
  Push(Num1)
  Push(Num2)
  Push(Num1)
EndProcedure

Procedure SingleSwap()
  Pop(Num1)
  Pop(Num2)
  Push(Num1)
  Push(Num2)
EndProcedure

Procedure DoubleSwap()
  Protected Num3.q, Num4.q
  Pop(Num1)
  Pop(Num2)
  Pop(Num3)
  Pop(Num4)
  Push(Num2)
  Push(Num1)
  Push(Num4)
  Push(Num3)
EndProcedure

Procedure Delete()
  Pop(Num1)
EndProcedure

OpenConsole()
EnableGraphicalConsole(1)

Position = 0
Repeat
  ConsoleLocate(Position, 0)

  e.s = UCase( Inkey() )

  Select e
    Case "0"
      Concatenate()
    Case "1"
      Increment()
    Case "2"
      Decrement()
    Case "3"
      Multiply()
    Case "4"
      Divide()
    Case "5"
      Add()
    Case "6"
      Subtract()
    Case "7"
      Exponent()
    Case "8"
      Modulus()
    Case "9"
      RotateRight()
    Case "A"
      RotateLeft()
    Case "B"
      Duplicate()
    Case "C"
      DoubleDuplicate()
    Case "D"
      SingleSwap()
    Case "E"
      DoubleSwap()
    Case "F"
      Delete()
  EndSelect

  If e <> ""
    Print(e)
    ConsoleLocate(Position, 1)
    Print("|")
    yLoc.i = ListSize(ProgramStack()) + 1

    ForEach ProgramStack()
      ConsoleLocate(Position, yLoc)
      Print(Str(ProgramStack()))
      yLoc - 1
    Next

    Position + 2
  EndIf
Until e = "X" Or e = "Q"

chỉnh sửa: Sau khi ngủ, tôi đã hình dung mình chơi golf - Tôi đã rời khỏi phiên bản có thể đọc được để tham khảo.

Mọi thứ đều hoạt động như nhau ngoại trừ tôi đã lấy Q hoặc X ra để thoát, chỉ cần đóng cửa sổ để thoát:

NewList S()
Macro P
Print
EndMacro
Macro G
ConsoleLocate
EndMacro
Macro LE
LastElement(S())  
EndMacro
Macro U(V)
LE
AddElement(S())
S()=V
EndMacro
Macro O(V)
LE
V=S()
DeleteElement(S())
EndMacro
U(0)
OpenConsole()
EnableGraphicalConsole(1)
X=0
Repeat
G(X,0)
e.s=UCase(Inkey())
Select e
Case"0"
O(H)
O(J)
U(Val(Str(J)+Str(H)))
Case"1"
LE
S()+1
Case"2"
LE
S()-1
Case"3"
O(H)
O(J)
U(J*H)
Case"4"
O(H)
O(J)
U(J/H)
Case"5"
O(H)
O(J)
U(J+H)
Case"6"
O(H)
O(J)
U(J-H)
Case"7"
O(H)
O(J)
U(Pow(J,H))
Case"8"
O(H)
O(J)
U(Mod(J,H))
Case"9"
FirstElement(S())
H=S()
DeleteElement(S(),1)
U(H)
Case"A"
O(H)
FirstElement(S())
InsertElement(S())
S()=H
Case"B"
O(H)
U(H)
U(H)
Case"C"
O(H)
O(J)
U(J)
U(H)
U(J)
U(H)
Case"D"
O(H)
O(J)
U(H)
U(J)
Case"E"
O(H)
O(J)
O(K)
O(L)
U(J)
U(H)
U(L)
U(K)
Case"F"
O(H)
EndSelect
If e<>""
P(e)
G(X,1)
Y=ListSize(S())+1
ForEach S()
G(X,Y)
P(Str(S()))
Y-1
Next
X+2
EndIf
ForEver

1

Lisp thường gặp - 586

(defmacro n(s)(with-gensyms($)(labels((?()`(pop,$))(!(x)`(push,x,$))(@(~)(!(list ~(?)(?))))(r@(~)(@`(lambda(x y)(,~ y x)))))`(let((,$`(,0))),@(loop for p below(length s)collect(case(parse-integer s :start p :end(1+ p):radix 16)(0(@'(lambda(a b)(+(* a(expt 10(if(> b 0)(ceiling(log b 10))1)))b))))(1`(incf(car,$)))(2`(decf(car,$)))(3(@'*))(4(@'/)) (5(@'+))(6(@'-))(7(r@'expt))(8(r@'mod))(9`(setf,$(#1=rotate,$)))(10`(setf,$(#1#,$ -1)))(11`(push(car,$),$))(12`(setf,$(nconc(#2=subseq,$ 0 2),$)))(13`(reversef(#2#,$ 0 2)))(14`(setf,$(append(#1#(#2#,$ 0 4)2)(#2#,$ 4))))(15`(pop,$)))),$))))

Ung dung

Liên kết chặt chẽ một ngăn xếp mới trong mã được khai thác vĩ mô: không tham chiếu đến một biến toàn cục. Ngoài ra, nó được biên dịch xuống mã máy.

(ql:quickload :alexandria)
(mapc #'use-package '(cl alexandria))
(defmacro n(s)
  (with-gensyms($)
    (labels ((?()`(pop,$))
             (!(x)`(push,x,$))
             (bop(op)(!(list op(?)(?))))
             (rbop(op)(bop`(lambda(x y)(,op y x)))))
      `(let((,$`(,0)))
         ,@(loop for p below(length s)
                 collect(case(parse-integer s :start p :end(1+ p):radix 16)
                           (#x0(bop'(lambda(a b)(+(* a(expt 10(if(> b 0)(ceiling(log b 10))1)))b))))
                           (#x1`(incf(car,$)))                    
                           (#x2`(decf(car,$)))
                           (#x3(bop'*))                    
                           (#x4(bop'/))
                           (#x5(bop'+))                    
                           (#x6(bop'-))
                           (#x7(rbop'expt))
                           (#x8(rbop'mod))
                           (#x9`(setf,$(rotate,$)))
                           (#xA`(setf,$(rotate,$ -1)))
                           (#xB`(push(car,$),$))
                           (#xC`(setf,$(nconc(subseq,$ 0 2),$)))
                           (#xD`(reversef(subseq ,$ 0 2)))
                           (#xE`(setf,$(append(rotate(subseq,$ 0 4)2)(subseq,$ 4))))
                           (#xF`(pop,$))))
         ,$))))

Thí dụ

   (n "11bc5c5b95")
   => macroexpands into (8 6 4 2)

1

Python 2, 508 byte

s,d=[0],lambda:s.pop(1)
for C in raw_input():
 D=int(C,16)
 if D<1:s[0]=int(`s[0]`+`d()`)
 if D==1:s[0]+=1
 if D==2:s[0]-=1
 if D==3:s[0]*=d()
 if D==4:s[0]=d()/s[0]
 if D==5:s[0]+=d()
 if D==6:s[0]-=d()
 if D==7:s[0]=d()**s[0]
 if D==8:s[0]=d()%s[0]
 if D==9:s=s[-1:]+s[:-1]
 if D==10:s=s[1:]+s[:1]
 if D==11:s=s[:1]+s
 if D==12:s=s[0:2]+s
 if D==13:s=s[1:2]+s[:1]+s[2:]
 if D==14:s=s[2:4]+s[0:2]+s[4:]
 if D>14:s=s[1:]
print s

Sử dụng mã hóa "0123456789ABCDEF". Tôi thực sự tự hào về cách mà cái này bật ra. Nó không đọc tệp, nó nhận đầu vào từ STDIN, nhưng nếu đó là một vấn đề thì nó có thể dễ dàng thay đổi.

2 giải pháp cho vấn đề 2014:

B11CB3A1AED0A00( 16 15 byte) - Bộ ghép nối chung.

BB102CD11B513B3622E( 20 19 byte) - Mát hơn nhiều - Đánh giá thành (5 * (10-1)) ^ 2-11


0

Python 2, 955 byte

import sys
global s
s=[0]
c=lambda x: x.append(str(x.pop())+str(x.pop()))
i=lambda x: x.append(x.pop()+1)
v=lambda x: x.append(x.pop()-1)
x=lambda x: x.append(x.pop()*x.pop())
q=lambda x: x.append(x.pop(-2)/x.pop())
a=lambda x: x.append(x.pop()+x.pop())
w=lambda x: x.append(x.pop(-2)-x.pop())
e=lambda x: x.append(x.pop(-2)**x.pop())
m=lambda x: x.append(x.pop(-2)%x.pop())
r=lambda x: x.append(x.pop(0))
l=lambda x: x.insert(0,x.pop())
d=lambda x: x.append(x[-1])
t=lambda x: x.extend(x[-2:])
s=lambda x: x.insert(-2,x.pop())
def z(x):
    for y in [0,1]:
        s.insert(-3,s.pop())
k={'$':c,'i':i,'v':v,'*':x,'/':q,'+':a,'-':w,'^':e,'%':m,'>':r,'<':l,'d':d,
   't':t,'s':s,'z':z,'.':lambda x: x.pop()}
if __name__=='__main__':
    with open(sys.argv[1],'r') as f:
        while 1:
            b=f.read(1)
            if not b or b not in k.keys():
                break
            else:
                n=k[b](s)
                for x in s: print s,

Mỗi chức năng làm gì

  • c: nối ($)
  • i: gia tăng (i)
  • v: giảm (v)
  • x: nhân (*)
  • q: chia (/)
  • a: thêm (+)
  • w: trừ (-)
  • e: số mũ (^)
  • m: modulo (%)
  • r: ca phải (>)
  • l: dịch chuyển trái (<)
  • d: trùng lặp (d)
  • t: nhân đôi hai lần (t)
  • s: hoán đổi 2 giá trị hàng đầu
  • z: hoán đổi kép (z)

Xem như đây không phải là mã golf (nó là một cuộc thi phổ biến ) và mã của bạn hầu như không được đánh gôn, tôi không nghĩ bạn cần bao gồm số byte.
FlipTack

@FlipTack Tôi chỉ bao gồm số byte vì ai đó có thể muốn biết.
ckjbgames
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.