เขียนล่ามสำหรับจัมเปอร์ภาษาลึกลับของฉัน


17

ฉันคิดจัมเปอร์ภาษาลึกลับขึ้นมา หลังจากนั้นคุณจะเห็นว่าทำไม

  • มันทำงานกับหน่วยความจำเข้าถึงโดยสุ่มด้วยไบต์เป็นเซลล์ RAM มีการทำดัชนีเป็นศูนย์และเต็มไปด้วยเลขศูนย์ในตอนแรก
  • เมื่อพยายามเข้าถึงเซลล์ที่มีข้อผิดพลาดดัชนีเชิงลบควรจะปรากฏขึ้นและโปรแกรมสิ้นสุดลง
  • เมื่อพยายามอ่านดัชนีที่ใหญ่กว่าครั้งสุดท้ายควรส่งคืนค่าศูนย์
  • เมื่อพยายามเขียนที่ดัชนีที่ใหญ่กว่าครั้งสุดท้าย RAM ควรเพิ่มเป็น 1024 และเซลล์ใหม่ที่เต็มไปด้วยศูนย์ (ในทางเทคนิคคุณสามารถเพิ่ม RAM ได้ไม่เกิน 1024 จากเหตุผลก็คือการเพิ่มประสิทธิภาพดังนั้นถ้าคุณใช้อักขระจำนวนมาก สามารถทำได้ไม่เกิน 1024)
  • โปรแกรมยังมีตัวชี้ไปยังเซลล์ใน RAM ซึ่งเริ่มแรกเป็นศูนย์
  • เมื่อโปรแกรมเริ่มดำเนินการพรอมต์สำหรับสตริงอินพุตควรแสดง (หรือรับอินพุตจากอาร์กิวเมนต์บรรทัดคำสั่งก็ขึ้นอยู่กับคุณ) สตริงอินพุตไม่ควรมีอักขระ null (ศูนย์ไบต์) จากนั้นสตริงป้อนเข้าจะถูกเขียนลงใน RAM โดยเริ่มที่ดัชนีศูนย์
  • เมื่อโปรแกรมสิ้นสุดการดำเนินการกล่องที่มีผลลัพธ์ของโปรแกรมจะปรากฏขึ้น - เนื้อหาของ RAM จากดัชนีศูนย์ถึงศูนย์ไบต์แรกยกเว้น

ตอนนี้ส่วนที่น่าสนใจที่สุดคือไวยากรณ์

โปรแกรมประกอบด้วยคำสั่ง (ตัวดำเนินการ unary-prefixes) และอาร์กิวเมนต์ คำสั่งและอาร์กิวเมนต์อาจคั่นด้วยช่องว่างหรือบรรทัดใหม่ แต่ไม่จำเป็น อย่างไรก็ตามการเว้นวรรคภายในอาร์กิวเมนต์ไม่ถูกต้องตัวอย่างเช่น# 2 = 4ถูกต้อง แต่# 2 = 4 4ไม่ใช่ โปรแกรมสามารถมีความคิดเห็นระหว่าง
()ความคิดเห็นที่ไม่สามารถซ้อนกัน - ตัวอย่างเช่นในการแสดงความคิดเห็นเป็น(abc(def)ghi) (abc(def)สามารถใส่ความคิดเห็นได้ทุกที่

  • #123 ตั้งค่าตัวชี้ RAM เป็น 123 (จำนวนเต็มทศนิยมบวกหรือศูนย์ใด ๆ )
  • >123 เพิ่มตัวชี้ RAM ที 123 (จำนวนเต็มฐานสิบบวกใด ๆ )
  • <123 ลดค่าตัวชี้ RAM ลง 123 (จำนวนเต็มทศนิยมบวกใด ๆ )
  • =123 เขียน 123 (จำนวนเต็มทศนิยม 8 บิตที่ไม่ได้ลงนาม) ในเซลล์ปัจจุบัน
  • +123 เพิ่ม 123 (จำนวนเต็มทศนิยม 8 บิตที่ไม่ได้ลงนาม) ลงในเซลล์ปัจจุบัน (modulo 256)
  • -123 ลบ 123 (จำนวนเต็มทศนิยม 8 บิตที่ไม่ได้ลงนามใด ๆ ) จากเซลล์ปัจจุบัน (โมดูโล 256)
  • :123- "goto" - ไปที่หมายเลขคำสั่ง 123 (อันแรกคือ 0) คุณสามารถควบคุมการไหลของโปรแกรมของคุณด้วยการข้ามได้ - ต้องกระโดด - นั่นคือเหตุผลที่ฉันตัดสินใจเรียกจัมเปอร์ภาษานี้

หากอาร์กิวเมนต์หายไปให้คิดว่าเป็น 1 สำหรับ><+-คำสั่งหรือ 0 สำหรับ#=:คำสั่ง

นอกจากนี้ยังมีตัวแก้ไขคำสั่ง - ?(คำนำหน้าไปยังคำสั่ง) จะดำเนินการคำสั่งต่อไปเฉพาะในกรณีที่เซลล์ปัจจุบันไม่เป็นศูนย์มิฉะนั้นข้ามคำสั่งนั้น สามารถนำไปใช้กับคำสั่งใด ๆ
ตัวอย่างเช่น?:17- ไปที่คำสั่ง 17 หากเซลล์ปัจจุบันไม่เป็นศูนย์

หากโปรแกรมไม่ถูกต้องหรือเกิดข้อผิดพลาดระหว่างรันไทม์สามารถแสดงข้อความ "ข้อผิดพลาด" ด้วยเหตุนี้คือ CodeGolf ข้อความสั้น ๆ ดังกล่าวจะไม่เป็นไร

งานของคุณ

เขียนล่ามสั้นที่สุดสำหรับภาษานี้

โปรแกรมทดสอบบางอย่าง

(prints "Hello world!" regardless of input)
=72>=101>=108>=108>=111>=32>=119>=111>=114>=108>=100>=33>=

(appends "!" to the end of input string)
?:2 :4 >1 :0 =33 >1 =0

ฉันจะเขียนโปรแกรมทดสอบในจัมเปอร์หลังจากนั้นสักครู่และมีล่ามเป็นของตัวเอง
Somnium

"ถึงศูนย์ไบต์แรกที่ยกเว้น" ดังนั้นหากยังมีไบต์อื่น ๆ หลังจากศูนย์ไบต์แรกเราไม่ควรส่งออกมา?
ProgramFOX

ใช่เราไม่ควร ทำเพื่อไม่ให้ล้างหน่วยความจำที่ใช้ทั้งหมด แต่คัดลอกเอาต์พุตไปยังจุดเริ่มต้น
Somnium

5
คุณสามารถให้โปรแกรมตัวอย่างและผลลัพธ์ได้บ้างหรือไม่
arshajii

1
คุณสามารถระบุข้อความแสดงข้อผิดพลาดที่แน่นอนสำหรับดัชนีลบได้หรือไม่ ฉันคิดว่าความแตกต่างระหว่างคำตอบที่เป็นผู้นำทั้งสองในขณะนี้นั้นน้อยกว่าความแตกต่างของข้อความแสดงข้อผิดพลาดดังนั้นฉันคิดว่ามันจะยุติธรรมกว่าหากได้รับการระบุอย่างแม่นยำ
Martin Ender

คำตอบ:


6

Ruby, 447 ไบต์

p,i=$*
l=(i||'').length
r=[0]*l
l.times{|j|r[j]=i[j].ord}
i=j=0
s=p.gsub(/\(.*?\)|\s/,'')
q=s.scan(/(\?)?([#<>=+:-])(\d*)/)
e=->{abort"Error"}
p[/\d\s+\d/]||q*''!=s ?e[]:(r+=[0]until i+1<r.length
c=q[j]
j+=1
f=c[1]
c[0]&&r[i]==0?next: a=c[2]==''? '><+-'[f]?1:0:c[2].to_i
'=+-'[f]&&a>255?e[]: f==?#?i=a :f==?>?i+=a :f==?<?i-=a :f==?=?r[i]=a :f==?+?r[i]+=a :f==?-?r[i]-=a :j=a
i<0?e[]:r[i]%=256)while j<q.length
puts r.first(r.index 0).map(&:chr)*''

รับทั้งโปรแกรมและอินพุตผ่านอาร์กิวเมนต์บรรทัดคำสั่ง

แก้ไข:แก้ไขข้อบกพร่องเล็กน้อยและเพิ่มการสนับสนุนสำหรับไวยากรณ์ที่ไม่ถูกต้องที่ราคา 40 ไบต์ (ในขณะที่เพิ่มการเพิ่มประสิทธิภาพอื่น ๆ เล็กน้อย)


สนุกมาก. โซลูชัน Ruby ของฉันเพิ่งชั่งน้ำหนักที่ 447 ตัวอักษรด้วย แม้ว่าฉันจะถ่ายทำในช่วงกลางปี ​​400 แต่จำนวนไบต์เดียวกันนั้นก็น่าประหลาดใจ
Scott Leadley

@ScottLeadley Ha นั่นเป็นเน็คไทที่น่าสนใจ ^^ ฉันจะให้คุณโหวตถ้าฉันยังไม่ได้ทำ ;)
Martin Ender

5

Python (729)

import re,sys
R,p,i,T,q,g=[0]*1024,0,0,re.findall(r'\d+|[()#><=+:?-]',sys.argv[1]),lambda i:0<=i<len(T),lambda i,d:int(T[i])if q(i)and T[i].isdigit()else d
def z(p):
 global R;assert p>=0
 if p>=len(R):R+=[0]*1024
s=sys.argv[2]
R[0:len(s)]=map(ord,s)
while i<len(T):
 t=T[i]
 if t=='(': 
  while T[i]!=')':i+=1
  i+=1
  if not q(i):break
  t=T[i]
 i+=1
 if t=='#':p=g(i,0)
 if t=='>':p+=g(i,1)
 if t=='<':p-=g(i,1)
 if t=='=':z(p);R[p]=g(i,0)
 if t=='+':z(p);R[p]+=g(i,1);R[p]%=256
 if t=='-':z(p);R[p]-=g(i,1);R[p]%=256
 if t==':':
  v=int(T[i])
  i,c=-1,-1
  while c!=v:i+=1;c+=T[i]in'#><=+-:'
 if t=='?':
  assert p>=0
  if p<len(R)and R[p]==0:i+=1
 i+=q(i)and T[i].isdigit()
print''.join(chr(int(c))for c in R).split('\0')[0]

สำหรับการเรียกใช้โปรแกรม:

  • อาร์กิวเมนต์ที่ 1: รหัสจัมเปอร์
  • อาร์กิวเมนต์ที่ 2: สตริงการเริ่มต้น

ตัวอย่าง:

$ python jumper.py "=97>>(this is a comment)=98>2=99#" "xyz123"
ayb1c3

อาจมีบางสิ่งที่ฉันมองข้ามดังนั้นโปรดแสดงความคิดเห็นหากคุณลองทำสิ่งที่ควรใช้ แต่ไม่ได้ผล โปรดทราบว่าสิ่งนี้ถูกเขียนในรหัส Python 2.x


คุณจะให้มันเข้าได้อย่างไร
Claudiu

@Claudiu ดูตัวอย่าง มันเป็นอาร์กิวเมนต์บรรทัดคำสั่ง
arshajii

นั่นคือโปรแกรม แต่ดูที่กระสุนนัดที่ 7 คุณควรจะสามารถเริ่มต้นอาร์เรย์ RAM เริ่มต้นเพื่อพูดว่า "สวัสดี" ผ่าน stdin หรืออาร์กิวเมนต์
Claudiu

ความผิดพลาดของฉันมันเป็นสัญลักษณ์แสดงหัวข้อย่อยที่ 6: "เมื่อโปรแกรมเริ่มดำเนินการพร้อมท์สำหรับสตริงการป้อนข้อมูลควรแสดง (หรือรับอินพุตจากอาร์กิวเมนต์บรรทัดคำสั่งขึ้นอยู่กับคุณ) สตริงอินพุตไม่ควรมีอักขระ null (ศูนย์ไบต์) สตริงถูกเขียนไปยัง RAM โดยเริ่มต้นที่ศูนย์ดัชนี "
Claudiu

@ Claudiu Ah ฉันรู้ว่าฉันมองข้ามบางสิ่งบางอย่างขอบคุณ ตอนนี้เมื่อเรียกใช้โปรแกรมคุณสามารถใส่สายกล่าวว่า
arshajii

4

Ruby 2 - 540 447 420 ตัวอักษร

เรียกใช้เป็น "ruby2.0 jumper.rb 'คำแนะนำ' 'ข้อมูลการเริ่มต้น' ' 1.x Ruby จะไม่ทำงาน (ไม่มีเมธอด String.bytes)


เพิ่มคำสั่งและความคิดเห็นแบบหลายบรรทัดและปรับปรุงการวางของฉัน


i=$*[0].gsub(/\([^)]*\)/m,' ').scan(/(\??)\s*([#=:><+-])\s*(\d*)/m).map{|a|[a[0]!='?',a[1],a[2]==''?/[#=:]/=~a[1]?0:1:a[2].to_i]}
N=i.size
d=$*[1].bytes
r=p=0
while p<N
u,o,x=i[p]
p+=1
d[r]=0 if d[r].nil?
case o
when'#';r=x
when'>';r+=x
when'<';r-=x
when/[=+-]/;eval "d[r]#{o.tr'=',''}=x";d[r]%=256
when':';p=x;abort'Error'if p>=N
end if u||d[r]>0
abort'Error'if r<0
end
printf"%s\n",d.take_while{|v|v&&v!=0}.pack('C*')

นี่คือชุดทดสอบที่มีการทดสอบการกระจายแบบกระจาย วิธีที่ง่ายที่สุดในการใช้งานคือใส่รหัสลงใน t / jumper.t และเรียกใช้ "perl t / jumper.t"


#/usr/bin/perl
use strict;
use warnings;
#       timestamp: 2014 August 3, 19:00
#
# - Assume program takes machine code and initialization string as command
#       line options.
# - Assume all required errors reported as "Error\n".
# - Go with the flow and suffix output with \n. Merged terminal newlines are
#       unacceptable [I'm talkin' to YOU Ruby puts()!].
# - As per OP - jumping to > end-of-program must be an error.

use Test::More qw(no_plan);
# use Test::More tests => 4;

my $jumper = "jumper.rb";
#
#       "happy" path
#
# starter tests provided by OP
is( `$jumper '=72>=101>=108>=108>=111>=32>=119>=111>=114>=108>=100>=33>=' '' 2>&1`, "Hello world!\n", "hello world (from user2992539)");
is( `$jumper '?:2 :4 >1 :0 =33 >1 =0' 'a' 2>&1`, "a!\n", 'append !, #1 (from user2992539)');

# simple variations
is( `$jumper '?:2 :4 >1 :0 =33 >1 =0' '' 2>&1`, "!\n", 'append !, #2');
is( `$jumper '?:2 :4 >1 :0 =33' '' 2>&1`, "!\n", 'append !, #3, no NUL');

# comment delimiters don't nest
is( `$jumper "(()=" 'oops' 2>&1`, "\n", "() don't nest");
# comments and termination
is( `$jumper '(start with a comment)?(comment w/ trailing sp) # (comment w/ surrounding sp) 1 =98' 'a' 2>&1`, "ab\n", 'walk to exit');
is( `$jumper '(start with a comment)? (comment w/ leading sp)= (comment w/ surrounding sp) 97()' '' 2>&1`, "\n", 'skip to exit');
is( `$jumper '#1=0 (actually two instructions, but it scans well) :5 #=(truncate further if not jumped over)' 'a b' 2>&1`, "Error\n", 'truncate & jump to exit');

# is RAM pointer initialized to 0?
is( `$jumper '-103(g-g) ?:1025(exit) =103 #4=10' 'good' 2>&1`, "good\n\n", 'intial string in right place?');

# TBD, do jumps work?
# TBD, do conditional jumps work?
# jump right to a harder case, copy byte 0 to byte 3 and format, e.g. input="Y" output="Y=>Y"
is( `$jumper '#1=61#2=62#4=0#3=#10=#(11:)?:13:20(13:)#3+#10+#0-:11(20:)#10(21:)?:23:28(23:)#0+#10-:21(28:)#' 'Y' 2>&1`, "Y=>Y\n", 'copy a byte');


# test memory allocation by dropping 255s at increasingly large intervals
is( `$jumper '#16=511 #64=511 #256=511 #1024=511 #4096=511 #16384=511 #65536=511 #262144=511 #1048576=511 #65536-255 (20:)?:23(exit) #=' 'wrong' 2>&1`, "\n", 'test alloc()');

# upcase by subtraction
is( `$jumper '-32' 't' 2>&1`, "T\n", 'upcase via subtraction');
# 2 nested loops to upcase a character, like so: #0=2; do { #0--; #1=16; do { #1--; #2--; } while (#1); } while (#0);
is( `$jumper '#=2 (2:)#- #1=16 (6:)#1- #2- #1?:6 #0?:2 #=32 #1=32' '  t' 2>&1`, "  T\n", 'upcase via loops');
# downcase by addition
is( `$jumper '+32' 'B' 2>&1`, "b\n", 'downcase via addition');
# same thing with a loop, adjusted to walk the plank instead of jumping off it
is( `$jumper '#1 ?:3 :7 -<+ :0 #' 'B ' 2>&1`, "b\n", 'downcase via adder (from  Sieg)');
# base 10 adder with carry
is( `$jumper '#0-48#10=9#11=#5=#0(9:)?:11:22(11:)#10?:14:22(14:)-#11+#5+#0-:9(22:)#0?:110#11(25:)?:27:32(27:)#0+#11-:25(32:)#0+48>-43?:110=43>-48#10=9#11=#2(45:)?:47:58(47:)#10?:50:58(50:)-#11+#5+#2-:45(58:)#2?:110#11(61:)?:63:68(63:)#2+#11-:61(68:)#2+48>-61?:110=61>?:110=32#10=9#11=#5-10(83:)?:85:94(85:)#10?:88:94(88:)-#11+#5-:83(94:)#5?:99#4=49:100(99:)+10(100:)#11(101:)?:103:108(103:)#5+#11-:101(108:)#5+48' '1+1=' 2>&1`, "1+1= 2\n", 'base 10 adder, #1');
is( `$jumper '#0-48#10=9#11=#5=#0(9:)?:11:22(11:)#10?:14:22(14:)-#11+#5+#0-:9(22:)#0?:110#11(25:)?:27:32(27:)#0+#11-:25(32:)#0+48>-43?:110=43>-48#10=9#11=#2(45:)?:47:58(47:)#10?:50:58(50:)-#11+#5+#2-:45(58:)#2?:110#11(61:)?:63:68(63:)#2+#11-:61(68:)#2+48>-61?:110=61>?:110=32#10=9#11=#5-10(83:)?:85:94(85:)#10?:88:94(88:)-#11+#5-:83(94:)#5?:99#4=49:100(99:)+10(100:)#11(101:)?:103:108(103:)#5+#11-:101(108:)#5+48' '9+9=' 2>&1`, "9+9=18\n", 'base 10 adder, #2');

# order of assignment shouldn't affect order of print
is( `$jumper '#1=98 #0=97' '' 2>&1`, "ab\n", 'print order != assignment order');

# are chars modulo 256?
is( `$jumper '#10(#10 defaults to 0) +255+(#10 += 256) ?#(skip if #10==0) =' 'good' 2>&1`, "good\n", 'memory values limited to 0<x<255');
# go for the cycle;
is( `$jumper '(0:)+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ (256:)#4=10' 'BCID' 2>&1`, "ACID\n\n", 'cycle character less 1, PC>255');
# same thing with a loop;
is( `$jumper '#4=255(#4 = 255) (2:)#1+(#1++) #4-(#4--) ?:2(loop 255 times) #4=10(#4 = NL)' 'ADID' 2>&1`, "ACID\n\n", 'cycle character less 1, PC>255');


#       Exercise the program counter.
# PC > 255;
is( `$jumper '(0:)= (1:)############################################################################################################################################################################################################################################################### (256:)?:259 (257:)+ (258:):1 (259:)=97#3=10' 'a==' 2>&1`, "a==\n\n", 'program counter range >255');


#
#       "sad" path
#
#       Error checking required by the specification.
#
# simplest test case of PC going out of bounds
is( `$jumper ':2' '' 2>&1`, "Error\n", 'program counter too big by 1');
is( `$jumper ':1024' '' 2>&1`, "Error\n", 'program counter in space');
is( `$jumper ':1073741824' '' 2>&1`, "Error\n", 'program counter in hyperspace');
# try to drive program counter negative, if 32-bit signed integer
is( `$jumper ':2147483648(exit)' 'ridiculous speed' 2>&1`, "Error\n", 'program counter goes negative?, #1');
# try to drive program counter negative, if 64-bit signed integer
is( `$jumper ':9223372036854775808 (exit)' 'ludicrous speed' 2>&1`, "Error\n", 'program counter goes negative?, #2');

# spaces not allowed in operand; error or silently ignore (my choice)
isnt(`$jumper '#= #= #= #= #= +1 4 ' 'aops' 2>&1`, "oops\n", 'do not accept spaces in operands');
# ditto w/ a comment ; error or silently ignore (my choice)
isnt(`$jumper '#= #= #= #= #= +1(not valid)4 ' 'aops' 2>&1`, "oops\n", 'do not accept spaces in operands');

# RAM pointer error-checking; "Error" or "" are OK
isnt( `$jumper '<>=' 'oops' 2>&1 | grep -v Error`, "oops\n", 'unused negative RAM pointer behavior unspecified');
# RAM pointer negative and use it
is( `$jumper '<=' '' 2>&1`, "Error\n", 'cannot use negative RAM pointer, #1');
# check for RAM pointer wrap-around
is( `$jumper '<=' '0123456789' 2>&1`, "Error\n", 'cannot use negative RAM pointer, #2');

# The way I read this
#       "Commands and arguments may be delimited with spaces or new lines but
#       not necessary."
# multi-line commands are legit.
is( `$jumper "#4#?\n=" 'oops' 2>&1`, "\n", 'multi-line commands allowed');

# Multi-line comments would be consistent with multi-line commands, but I can't
# find something I can translate into a "must" or "must not" requirement in
#       "Program can have comments between (). ... Comments can be placed
#       anywhere."
# Until uncertainty resolved, no test case.


#
#       "bad" path
#
#       These tests violate the assumption that the instruction stream is wellll-farmed.
#
# characters not in the language; error or (my choice) silently skip
isnt(`$jumper 'x =' 'oops' 2>&1`, "oops\n", 'opcode discrimination');
# is ? accepted as an operator (vs operation modifier); error or (my choice) silently skip
is(`$jumper '(bad 0, good 0:)??0 (bad 1, good 0:):3 (bad 2, good 1:)#0' '' 2>&1`, "Error\n", '? not accepted as an opcode');

exit 0;

เวอร์ชันที่ไม่ดี


#
#       Turing Machine Mach 2.0.
#       Tape? Tape? We don't need no stinkin' tape! We gots RAM!
#
#       dM = data memory
#       iM = instruction memory
#       pC = program counter
#       rP = RAM pointer
#       u, o, x = current instruction being executed
#
#       N = number of instructions in instruction memory
#

#       instruction decoder
iM = $*[0].gsub(/\([^)]*\)/m,' ').scan(/(\??)\s*([#=:><+-])\s*(\d*)/m).map { |a|
    [
        a[0] != '?',
        a[1],
        (a[2] == '')  ?  (/[#=:]/ =~ a[1] ? 0 : 1)  :  a[2].to_i
    ]
}
pC = 0
N = iM.size

dM = $*[1].bytes
rP = 0

while pC < N do
    #   u, unconditional instruction,   execute if true || (dM[rP] > 0)
    #                                   skip if false && (dM[rP] == 0)
    #   o, operator
    #   x, operand
    (u, o, x) = iM[pC]
    pC += 1
    dM[rP] = 0  if dM[rP].nil?
    if u || (dM[rP] > 0)
        case o
        when '#'
            rP = x
        when '>'
            rP += x
        when '<'
            rP -= x
        when /[=+-]/
            eval "dM[rP]#{o.tr'=',''}=x"
            dM[rP] %= 256
        when ':'
            pC = x
            abort 'Error'  if pC >= N
        end
    end
    abort 'Error'  if rP < 0
end
printf "%s\n", dM.take_while{|v|v&&v!=0}.pack('C*')

โปรโต - แอสเซมเบลอร์


#
#       Jumper "assembler" - symbolic goto labels.
#
# what it does:
#       - translates labels/targets into absolute position
#               @label ?:good_exit
#               ...
#               :label
#
#       - a label is [a-zA-Z][a-zA-Z0-9_]*
#       - a target is @label
#       - one special label:
#               - "hyperspace" is last instruction index + 1
#       - strips out user comments
#               - everything from "//" to EOL is stripped
#               - jumper comments are stripped
#       - adds "label" comments of the form "(ddd:)"
# limitations & bugs:
#       - multi-line jumper comments aren't alway handled gracefully
#       - a target not followed by an instruction will reference
#               the previous instruction. this can only happen
#               at the end of the program. recommended idiom to
#               avoid this:
#                       @good_exit #
# what it doesn't do:
#       - TBD, simple error checking
#               - labels defined and not used
#       - TBD, symbolic memory names
#
# Example:
#
#   input -
#       (
#               adder from Sieg
#       )
#       @loop_head # 1  // while (*(1)) {
#       ?:continue
#       :good_exit
#
#       @continue -     //     *(1) -= 1;
#       <-           //     *(0) += 1;
#       +
#       :loop_head      // }
#       @good_exit #
#
#   output -
#       (0:) #1 ?:3 :7 (3:) - < + :0 (7:)#

rawSource = ARGF.map do |line|
  line.gsub(/\([^)]*\)/, ' ')   # eat intra-line jumper comments
    .gsub(/\/\/.*/, ' ')        # eat C99 comments
    .gsub(/^/, "#{$<.filename}@#{$<.file.lineno}\n") # add line ID
end.join
rawSource.gsub! /\([^)]*\)/m, '' # eat multi-line jumper comments
#
# Using example from above
#
# rawSource =
#       "sieg.ja@1\n \n" +
#       "sieg.ja@4\n@loop_head # 1\n"
#       ...
#       "sieg.ja@12\n@good_exit # \n"

instructionPattern = %r{
    (?<label> [[:alpha:]]\w* ){0}
    (?<operator> \??\s*[#=:><+-]) {0}
    (?<operand> \d+|[[:alpha:]]\w* ){0}

    \G\s*(@\g<label>\s*)?(\g<operator>\s*)?(\g<operand>)?
  }x
FAIL = [nil, nil, nil]
instructionOffset = 0
iStream = Array.new
target = Hash.new
targetComment = nil
for a in rawSource.lines.each_slice(2) do
  # only parse non-empty lines
  if /\S/ =~ a[1]
    m = nil
    catch( :parseError ) do
      chopped = a[1]
      while m = instructionPattern.match(chopped)
        if m.captures.eql?(FAIL) || (!m[:operator] && m[:operand])
          m = nil
          throw :parseError
        end
        if m[:label]
          if target.has_key?(m[:label].to_sym)
            printf $stderr, a[0].chomp + ": error: label '#{m[:label]}' is already defined"
            abort a[1]
          end
          target[ m[:label].to_sym ] = instructionOffset
          targetComment = "(#{instructionOffset}:)"
        end
        if m[:operator]
          iStream[instructionOffset] = [
              targetComment,
              m[:operator],
              /\A[[:alpha:]]/.match(m[:operand]) ? m[:operand].to_sym : m[:operand]
            ]
          targetComment = nil
          instructionOffset += 1
        end
        chopped = m.post_match
        if /\A\s*\Z/ =~ chopped
          # nothing parseable left
          break
        end
      end
    end
    if !m
      printf $stderr, a[0].chomp + ": error: parse failure"
      abort a[1]
    end
  end
end

# inject hyperspace label
target[:hyperspace] = instructionOffset

# replace operands that are labels
iStream.each do |instruction|
  if instruction[2]
    if !(/\A\d/ =~ instruction[2]) # its a label
      if target.has_key?(instruction[2])
        instruction[2] = target[instruction[2]]
      else
        abort "error: label '@#{instruction[2]}' is used but not defined"
      end
    end
  end
  puts instruction.join
end

2

Clojure - 585 577 ไบต์

Edit:   I forgot modulo 256, of course
Edit 2: Now supports whitespace and comments anywhere. (585 -> 578)

ไม่มีเทคนิคการเล่นกอล์ฟแบบพิเศษใช้เพราะฉันไม่รู้อะไรเลยสำหรับ Clojure ล่ามทำงานได้อย่างหมดจด มาพร้อมกับข้อความแสดงข้อผิดพลาดที่ดีในกรณีที่ที่อยู่ RAM เชิงลบ (ข้อผิดพลาดเป็นเอาท์พุท แต่ไม่มีข้อยกเว้นหรือข้อผิดพลาดจะถูกโยน)

(defn j[o i](let[o(re-seq #"\??[#<>=+:-]\d*"(clojure.string/replace o #"\(.*?\)|\s"""))r(loop[c 0 p 0 m(map int i)](if-let[f(nth o c nil)](let[[c p m]((fn r[t](let[f(first t)s(if(next t)(apply str(next t))(case f(\#\=\:)"0"(\>\<\+\-)"1"))v(read-string s)a(nth m p 0)](case f\?(if(=(nth m p 0)0)[c p m](r s))\#[c v m]\>[c(+ p v)m]\<[c(- p v)m]\:[(dec v)p m][c p(assoc(vec(concat m(repeat(- p(count m))0)))p(mod({\+(+ a v)\-(- a v)}f v)256))])))f)](if(< p 0)(str"Negative index "p" caused by "f)(recur(inc c)p m)))m))](if(string? r)r(apply str(map char(take-while #(> % 0)r))))))

ตัวอย่าง:

(j "=72>=101>=108>=108>=111>=32>=119>=111>=114>=108>=100>=33>=" "")
=> "Hello world!"
(j "?:2 :4 >1 :0 =33 >1 =0" "hi there")
=> "hi there!"
(j "#1 ?:3 :7 -<+ :0" "01") ; adder
=> "a"
(j "?:2 :4 >1 :0 =33 <10 =0" "hi there")
=> "Negative index -2 caused by <10"
(j "=72>=101>=108>=108>=111>=3(comment here <100)2>=119>=111>=114>=108>=100>=33>=" "")
=> "Hello world!"

รหัส ungolfed เล็กน้อยเดิม :

(defn memory
  ([]
    (vec (repeat 1024 0)))
  ([m i v]
    (assoc (vec (concat m (repeat (- i (+ -1024 (mod i 1024)) (count m)) 0)))
           i v)))

(defn parse [c p m t]
  (let [f (first t)
        s (if-let [v (next t)]
            (apply str v)
            (case f
              (\#\=\:) "0"
              (\>\<\+\-) "1"))
        v (read-string s)
        a (nth m p 0)]
    (case f
      \? (if (= (nth m p 0) 0) [c p m] (parse c p m s))
      \# [c v m]
      \> [c (+ p v) m]
      \< [c (- p v) m]
      \: [(dec v) p m]
      [c p (memory m p (mod ({\+ (+ a v) \- (- a v)} f v) 256))])))

(defn jumper [o i]
  (let [o (re-seq #"\??[#<>=+:-]\d*" (clojure.string/replace o #"\(.*?\)|\s" ""))
        r (loop [c 0
                 p 0
                 m (map int i)]
            (if-let [f (nth o c nil)]
              (let [[c p m] (parse c p m f)]
                (if (< p 0)
                  (str "Negative index " p " caused by " (nth o c))
                  (recur (inc c) p m))) m))]
    (if (string? r)
      r
      (apply str (map char (take-while #(> % 0) r))))))

โปรแกรมของฉันใน Jumper ซึ่งเพิ่ม "!" ทำงาน! มันเป็นบิตยากในการเขียนโปรแกรมในจัม ..
Somnium

มันเป็นแนวคิดที่เรียบร้อยที่คุณมี
seequ

@ user2992539 ฉันได้เพิ่มตัวอย่างของแอดเดอร์อย่างง่าย
seequ

โดยทั่วไปแล้วจะคล้ายกับ Brainfuck แต่ไม่มีลูป, ข้ามไปและถ้าเป็นแทนและมีพารามิเตอร์คำสั่ง
Somnium

1
หากคุณวางส่วน-ท้ายของคลาสอักขระของ regex ของคุณคุณไม่จำเป็นต้องหลบหนี อักขระ -1 ตัว
tomsmeding

2

CoffeeScript (465)

กล่องพรอมต์แรกใช้สำหรับโปรแกรมและกล่องพรอมต์ที่สองคืออินพุต ทดสอบที่http://coffeescript.org

ต้นฉบับ :

p=prompt().replace(/\(.*?\)|[\s\n\r]/g,"").match(/\??[^\d]\d*/g) ?[]
y=p[..]
i=prompt()
r=[].map.call i,(c)->c[0].charCodeAt()
n=0
m=[(d)->n=d
(d)->m[5] (r[n]+d)%%256
(d)->p=y[d..]
(d)->m[1] -d
(d)->n-=d
(d)->r[n]=d
(d)->n+=d]
while b=p.shift()
 if b[0]=="?"
  continue unless r[n]
  b=b[1..]
 d="><+-#=:".indexOf(b[0])//4
 ~d||throw "!badcmd '#{b[0]}'"
 m[b[0].charCodeAt()%7](+b[1..]||+!d)
 n<0&&throw "!ramdix<0"
alert String.fromCharCode(r...).replace(/\0.*/,"")

นี่ยังคงเป็นกอล์ฟอยู่ แต่แสดงความคิดเห็น:

# Get program
p=prompt().replace(/\(.*?\)/g,"").match(/\??[^\s\d]\d*/g) ?[]
# Create a copy of the program (for goto)
y=p[..]
# Get input
i=prompt()
# Put the input in the ram
r=[].map.call i,(c)->c[0].charCodeAt()
# RAM pointer
n=0
# An array of commands
# Since each of "<>+-#=:" is a different
# value mod 7 (what a coincedence?!)
# So 0th value is "#" command because 
# "#".charCodeAt() % 7 === 0
m=[(d)->n=d
(d)->m[5] (r[n]+d)%%256
(d)->p=y[d..]
(d)->m[1] -d
(d)->n-=d
(d)->r[n]=d
(d)->n+=d]
# Iterate through commands
while b=p.shift()
 # If you find a "?" skip unless r[n] is > 0
 if b[0]=="?"
  continue unless r[n]
  b=b[1..]
 # Get the default value
 d="><+-#=:".indexOf(b[0])//4
 # If the command isn't good, throw an error
 throw "!badcmd '#{b[0]}'" if d==-1
 # Call the appropriate command
 # By computing the char code mod 7
 m[b[0].charCodeAt()%7](+b[1..]||+!d)
 # Make sure n is bigger than or equal to 0
 throw "!ramdix<0" if n<0
# Show output
alert String.fromCharCode(r...).replace(/\0.*/,"")

แก้ไข : การเพิ่มช่องว่างมีจำนวนไบต์มากกว่าที่ฉันคิด ล่ามนี้จะโยนข้อผิดพลาดเกี่ยวกับไวยากรณ์ที่ไม่ถูกต้องคนอื่น ๆ มีพฤติกรรมที่ไม่ได้ระบุในไวยากรณ์ที่ไม่ถูกต้อง

p=prompt().replace(/\(.*?\)/g,"").match(/\??[^\d\s\r\n]\s*\n*\r*\d*/g) ?[]
y=p[..]
i=prompt()
r=[].map.call i,(c)->c[0].charCodeAt()
n=0
m=[(d)->n=d
(d)->m[5] (r[n]+d)%%256
(d)->p=y[d..]
(d)->m[1] -d
(d)->n-=d
(d)->r[n]=d
(d)->n+=d]
while b=p.shift()?.replace /^(.)(\s\r\n)*/,"$1"
 if b[0]=="?"
  continue if !r[n]
  b=b[1..]
 d="><+-#=:".indexOf(b[0])//4
 ~d||throw "!badcmd"
 m[b[0].charCodeAt()%7](+b[1..]||+!d)
 n<0&&throw "!ramdix<0"
alert String.fromCharCode(r...).replace(/\0.*/,"")

เห็นได้ชัดว่านี่ใช้ไม่ได้?:2 :4 >1 :0 = 33 <10 =0(โปรแกรมภาคผนวก -! ที่มีพื้นที่เพิ่มเติม)
seequ

@Sieg มันควรจะเป็นไม่ได้<1 <10
soktinpk

@ ซิกไม่เป็นไรฉันจะอัปเดตเมื่อฉันมีเวลา
soktinpk

@Sieg ทำงานแล้วฉันจะเล่นกอล์ฟต่อไป
soktinpk

1
ฉันใช้ท่าทางของ "มันไม่ได้ประกาศดังนั้นจึงเป็นพฤติกรรมที่ไม่ระบุ" ดังนั้นฉันจะบอกว่ามันดี แต่อีกครั้งฉันไม่ใช่ผู้ใช้ที่ยิ่งใหญ่
Seequ

1

Javascript, 519

C=prompt().replace(/\(.*?\)/g,"").match(/\??[#><=+:-]\d*/g)
M=prompt().split("").map(function(c){return c.charCodeAt(0)})
R=0
f=function(I){T=I[0]
A=I.slice(1)
if(T=="?")return M[R]?f(A):P++
A=A==""?1:+A
if(T==">")R+=A
if(T=="<")R-=A
if("=+-".indexOf(T)+1){if(R<0)throw alert("ERR RAMidx<0")
while(R>=M.length)M.push(0)}
if(T=="+")M[R]=M[R]+A&255
if(T=="-")M[R]=M[R]-A&255
A=+I.slice(1)
if(T=="#")R=A
if(T=="=")M[R]=A
if(T==":")P=A;else++P}
for(P=0;C[P];)f(C[P])
alert(String.fromCharCode.apply(7,M).replace(/\0.*/,""))

สิ่งนี้ทำให้โปรแกรมและอินพุตผ่านกล่องข้อความแจ้งเตือน การวางสิ่งนี้ในคอนโซล Javascript ของเบราว์เซอร์ของคุณจะทำงานได้เช่นเดียวกับการขว้างสิ่งนี้ในไฟล์วางก่อนโค้ด<!DOCTYPE html>ขึ้นบรรทัดใหม่<html><head><script>และหลังรหัส</script></head><body></body></html>และบันทึกไฟล์ผลลัพธ์เป็น "swagger.html"

นี่เป็นครั้งแรกที่ฉันพยายามทำสิ่งนี้และฉันก็ชอบภาษาอยู่แล้ว Kinda จำเป็นต้องใช้ป้ายข้อความแทนการติดฉลากดัชนีคำแนะนำพื้นฐาน

เวอร์ชันที่ไม่ได้อัปโหลด (kinda):

var C,M,R,P,f;
C=prompt().replace(/\(.*?\)/g,"").match(/\??[#><=+:-]\d*/g); //Code
M=prompt().split("").map(function(c){return c.charCodeAt(0)}); //Memory
R=0; //RAM pointer
f=function(I){ //parser function, Instruction
    var T,A;
    T=I[0]; //Type
    A=I.slice(1); //Argument
    if(T=="?")return M[R]?f(A):P++;
    A=A==""?1:+A;
    if(T==">")R+=A;
    if(T=="<")R-=A;
    if("=+-".indexOf(T)+1){
        if(R<0)throw alert("ERR RAMidx<0");
        while(R>=M.length)M.push(0);
    }
    if(T=="+")M[R]=M[R]+A&255;
    if(T=="-")M[R]=M[R]-A&255;
    A=+I.slice(1);
    if(T=="#")R=A;
    if(T=="=")M[R]=A;
    if(T==":")P=A;else++P;
}
for(P=0;C[P];f(C[P])); //Program pointer
alert(String.fromCharCode.apply(7,M).replace(/\0.*/,""));

หากการแทนที่สตริงของ Clojure ไม่เป็นเช่นนั้นclojure.string/replace
Seequ

1
นอกจากนี้สิ่งที่ผมสังเกตเห็นว่ามันไม่ได้เรื่องเลยถ้าคุณเพิ่มหน่วยความจำที่จะทวีคูณ 1024 หรือไม่)
seequ

1
ฉันไม่คิดว่าสคริปต์ของคุณสามารถจัดการได้?:2 :4 >1 :0 = 33 <10 =0(ภาคผนวก -! ด้วยพื้นที่เพิ่มเติม) ไม่ได้ทดสอบ
Seequ

@ เห็นมันไม่สามารถแน่นอน ควรเป็น? ฉันเพียงแค่สามารถกรองช่องว่างทั้งหมดถ้าจำเป็น ...
tomsmeding

1
"คำสั่งและอาร์กิวเมนต์อาจถูกคั่นด้วยช่องว่างหรือบรรทัดใหม่ แต่ไม่จำเป็นอย่างไรก็ตามช่องว่างภายในอาร์กิวเมนต์ไม่ถูกต้อง" หากฉันเข้าใจว่าถูกต้อง @ user2992539 มีคำพูดเกี่ยวกับสิ่งนี้หรือไม่?
seequ

1

C 687 GCC 4.9.0 และ Visual C ++ 2013 (หากการสิ้นสุดบรรทัดนับเป็น 1)

แก้ไข: ขอบคุณ Dennis ตอนนี้มันสั้นกว่ามาก (และใช้งานใน GCC ในการบูต)

รุ่น golfed

#define S char*
#define Z (S)R
#define U unsigned char
#define M R=(U*)realloc(Z,r+1024),memset(Z+r,0,1024),r+=1024
#define J z<0?exit(puts("!")),0:z>r?
#define G J 0:R[z]
#define P(x)J M,R[z]=x:(R[z]=x);
#define O !*(C+1)?1:
#define V atoi(C+1)
#define I if(*C==
#define W while(*p&&*p<33)p++;
#define K (*q++=*p++)
#define Y return
U C[999][9];U*R=0;r=0,z=0,c=0;S T(S a){S p=a,*q=C[c++],*r;W if(K==63){W K;}W int i=strtol(p,&r,0);memcpy(q,p,r-p);q[r-p]=0;Y r;}int E(S C){I 63)Y G?E(C+1):0;I 35)z=V;I 62)z+=O V;I 60)z-=O V;I 61)P(V)I 43)P(G+O V-1)I 45)P(G-O V-1)I 58)c=V-1;}main(int u,S *v){M;u==3?strcpy(Z,v[2]):0;S X=v[1];while(*X)X=T(X);*C[c]=0;c=-1;while(*C[++c])E(C[c]);Y puts(Z);}

รุ่น golfed น้อยกว่าเล็กน้อย:

#include<stdlib.h>
#include<memory.h>
#include<string.h>
#include<stdio.h>
#define CHAR_STAR char*
#define CASTED_R (CHAR_STAR)RAM
#define UNSIGNED_CHAR unsigned char
#define INCREASE_MEMORY RAM=(UNSIGNED_CHAR*)realloc(CASTED_R,RAM_size+1024),memset(CASTED_R+RAM_size,0,1024),RAM_size+=1024
#define IF_ERROR current<0?exit(puts("!")),0:current>RAM_size?
#define GET_CELL IF_ERROR 0:RAM[current]
#define PUT_CELL(x) IF_ERROR INCREASE_MEMORY,RAM[current]=x:RAM[current]=x;
#define ONE_IF_EMPTY !*(command+1)?1:
#define VALUE atoi(command+1)
#define REMOVE_WHITESPACE while (*pointer&&*pointer<33)pointer++;
#define COPY_CHAR (*command++ = *pointer++)
#define RETURN return
char commands[999][9];
UNSIGNED_CHAR*RAM = 0;
int RAM_size = 0, current = 0, command_size = 0;
CHAR_STAR get_command(CHAR_STAR a)
{
    CHAR_STAR pointer = a, *command = commands[command_size++], *next;
    REMOVE_WHITESPACE
    if (COPY_CHAR == '?')
    {
        REMOVE_WHITESPACE
        COPY_CHAR;
    }
    REMOVE_WHITESPACE
    int i = strtol(pointer, &next, 0);
    memcpy(command, pointer, next - pointer);
    command[next - pointer] = 0;
    RETURN next;
}
void eval(CHAR_STAR command){
    if (*command == '?')RETURN GET_CELL ? eval(command + 1) : 0;
    if (*command == '#')current = VALUE;
    if (*command == '>')current += ONE_IF_EMPTY VALUE;
    if (*command == '<')current -= ONE_IF_EMPTY VALUE;
    if (*command == '=')PUT_CELL(VALUE)
    if (*command == '+')PUT_CELL(GET_CELL + ONE_IF_EMPTY VALUE - 1)
    if (*command == '-')PUT_CELL(GET_CELL - ONE_IF_EMPTY VALUE - 1)
    if (*command == ':')command_size = VALUE - 1;
}
int main(int argc, CHAR_STAR *argv)
{
    INCREASE_MEMORY;
    argc == 3 ? strcpy(CASTED_R, argv[2]) : 0;
    CHAR_STAR command = argv[1];
    while (*command) command = get_command(command);
    *commands[command_size] = 0; command_size = -1;
    while (*commands[++command_size]) eval(commands[command_size]);
    RETURN puts(CASTED_R);
}

1. ฉันไม่รู้เกี่ยวกับคอมไพเลอร์อื่น ๆ แต่สิ่งนี้จะไม่คอมไพล์ใน GCC นี้สามารถแก้ไขได้โดยการเปลี่ยนที่สองR[z]=xในด้วยP(x) (R[z]=x)2. GCC ไม่จำเป็นต้องมีคำสั่ง include ใด ๆ 3. ->char C U C
เดนนิส

@Dennis ฉันกำลังทดสอบด้วย Visual C ++ 2013 ฉันจะทดสอบกับ GCC ในวันพรุ่งนี้
Jerry Jeremiah

0

Groovy 582

เวอร์ชันที่ไม่ถูกปรับแต่ง:

ฉันคิดว่ามีข้อผิดพลาดกับความคิดเห็นที่ไม่ได้รับการยอมรับอย่างถูกต้องซึ่งอาจเกิดจากการโง่ regex ฉันใช้ แต่ 2 โปรแกรมทำงานตามที่ควร:

class P {
    def c = 0
    def p = 0
    def m = []

    P(i="") {
        m = i.chars.collect { it }
        m << 0
    }

    def set(v) { m[p] = v }
    def add(v) { m[p] += v }
    def sub(v) { m[p] -= v }

    def eval(i) {
        while(c < i.size()) {
            if (i[c].p && m[p] == 0) {c++} 
            else { i[c].f(this,i[c].v) }
        }
        return m
    }
}


def parse(s) {
    def ops = [
       '#' : [{p, v -> p.p = v; p.c++}, "0"],
       '>' : [{p, v -> p.p += v; p.c++}, "1"],
       '<' : [{p, v -> p.p -= v; p.c++}, "1"],
       '=' : [{p, v -> p.set(v); p.c++}, "0"],
       '+' : [{p, v -> p.add(v); p.c++}, "1"],
       '-' : [{p, v -> p.sub(v); p.c++}, "1"],
       ':' : [{p, v -> p.c = v}, "0"]
    ]

    (s =~ /\(.*\)/).each {
        s = s.replace(it, "")
    }

    (s =~ /(\?)?([#><=+-:])([0-9]*)?/).collect {        
        def op = ops[it[2]]
        [f : op[0], v : Integer.parseInt(it[3] ?: op[1]), p : it[1] != null ]
    }
}

0

Haskell: จำนวนตัวอักษรที่ไม่ดี

เอาล่ะตอนนี้นี่เป็นสิ่งที่อาจจะใช่หรือไม่อาจเล่นกอล์ฟในไม่ช้า มันมีขนาดใหญ่มากอย่างอิสระสำหรับสิ่งที่มันมีจำนวนมากและเขียนโค้ดสกปรกมาก (มันค่อนข้างบางเวลาตั้งแต่ฉันสัมผัส Haskell ครั้งสุดท้าย) แต่มันสนุกที่จะเขียน

import Data.Char

parse [] p c a m i =
    if c == ' ' || c == '?' then
        []
    else
        (p ++ [(c, a, m)])

parse (h:t) p c a m i
    | i
        = parse t p c a m (h == ')')
    | isDigit h && a < 0
        = parse t p c (digitToInt h) m i
    | isDigit h
        = parse t p c (10 * a + (digitToInt h)) m i
    | elem h "#><=+-:?"
        = if c == ' ' || c == '?' then
            parse t p h a (c == '?') i
        else
            parse t (p ++ [(c, a, m)]) h (-1) False i
    | otherwise
        = case h of
            '(' -> parse t p c a m True
            ' ' -> parse t p c a m i
            _   -> []

run p pp r rp
    | pp >= length p
        = r
    | pp 0 || rp < 0
        = []
    | otherwise
        = if mr then
            case c of
                '#' -> run p (pp + 1) r pa
                '>' -> run p (pp + 1) r (rp + pa)
                '<' -> run p (pp + 1) r (rp - pa)
                '=' -> run p (pp + 1) (rh ++ ((chr pa) : rt)) rp
                '+' -> run p (pp + 1) (rh ++ (chr (mod ((ord h) + pa) 256) : rt)) rp
                '-' -> run p (pp + 1) (rh ++ (chr (mod ((ord h) - pa + 256) 256) : rt)) rp
                ':' -> run p pa r rp
        else
            run p (pp + 1) r rp
        where
            (c, a, m)
                = p !! pp
            (rh, h:rt)
                = splitAt rp r
            pa
                = if a < 0 then
                    if elem c "><+-" then
                        1
                    else
                        0
                else
                    a
            mr
                = ord (r !! rp) > 0 || not m

main = do
    p <- getLine
    let n = parse p [] ' ' (-1) False False
    if n == []
        then do
            putStrLn "Error"
        else do
            s <- getLine
            let r = run n 0 (s ++ (repeat (chr 0))) 0
            if r == []
                then do
                    putStrLn "Error"
                else do
                    putStrLn (takeWhile (/=(chr 0)) r)

0

Haskell, 584

โปรแกรมอินพุตและจัมเปอร์ถูกจัดเตรียมเป็นอินพุตสองบรรทัดแรกจาก stdin

a g(i,n,x)=(i+1,n,take n x++((g$x!!n)`mod`256):drop(n+1)x)
b g(i,n,x)=(i+1,g n,x)
c=b.q:a.(+):g:a.(-):b.(-):a.q:b.(+):c
d=(%['0'..'9'])
e=fromEnum
f=0>1
g n(_,x,y)=(n,x,y)
h(x:_)=d x;h _=f
i g p@(j,n,m)|x$m!!n=g p|t=(j+1,n,m)
j=0:1:0:1:1:0:1:j
k=takeWhile
l[]=[];l(x:y)|x%") \n"=l y|x%"("=l$u(/=')')y|t=x:l y
main=v>>=(\y->v>>=putStr.map toEnum.k x.r(0,0,map e y++z).p.l)
o n s|h s=(read$k d s,u d s)|t=(n,s)
p[]=[];p(x:y)|x%"?"=w$p y|t=(c!!e x)n:p m where(n,m)=o(j!!e x)y
q=const
r s@(i,n,m)p|i<length p=r((p!!i)s)p|t=m
t=0<1
u=dropWhile
v=getLine
w(m:n)=i m:n
x=(/=0)
z=0:z
(%)=elem

ฉันจะโพสต์เวอร์ชันที่ไม่ได้แต่งในภายหลัง แต่ในระหว่างนี้ฉันต้องการปล่อยให้สิ่งนี้เป็นปริศนาสำหรับผู้อ่าน:

คำสั่งจัมเปอร์อยู่ที่ไหนเช่น '#' ฯลฯ

มีความสุข!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.