创建最短的图灵完备解释器

发布于 2024-07-26 10:15:35 字数 611 浏览 5 评论 0 原文

我只是试图创建尽可能小的语言解释器。 您想加入并尝试吗?

游戏规则

  • 您应该指定您正在解释的编程语言。 如果它是您发明的语言,它应该在注释中附带一个命令列表。
  • 您的代码应该从分配给代码和数据变量的示例程序和数据开始。
  • 您的代码应该以结果输出结束。 最好在每个中间步骤都有调试语句。
  • 您的代码应该可以按照编写的方式运行。
  • 您可以假设数据是 0 和 1(整数、字符串或布尔值,您可以选择)并且输出是单个位。
  • 该语言应该是图灵完备的,因为对于在标准模型上编写的任何算法(例如图灵机、马尔可夫链或您选择的类似算法),如何编写执行后的程序是相当明显的(或解释的)由你的解释器执行算法。
  • 代码长度定义为去除输入部分、输出部分、调试语句和不必要的空格后的代码长度。 请将生成的代码及其长度添加到帖子中。
  • 您不能使用使编译器为您执行代码的函数,例如 eval()exec() 或类似函数。

这是一个社区 Wiki,这意味着问题和答案都不会从投票中获得声誉点。 但无论如何都要投票!

I've just tried to create the smallest possible language interpreter. Would you like to join and try?

Rules of the game:

  • You should specify a programming language you're interpreting. If it's a language you invented, it should come with a list of commands in the comments.
  • Your code should start with example program and data assigned to your code and data variables.
  • Your code should end with output of your result. It's preferable that there are debug statements at every intermediate step.
  • Your code should be runnable as written.
  • You can assume that data are 0 and 1s (int, string or boolean, your choice) and output is a single bit.
  • The language should be Turing-complete in the sense that for any algorithm written on a standard model, such as Turing machine, Markov chains, or similar of your choice, it's reasonably obvious (or explained) how to write a program that after being executred by your interpreter performs the algorithm.
  • The length of the code is defined as the length of the code after removal of input part, output part, debug statements and non-necessary whitespaces. Please add the resulting code and its length to the post.
  • You can't use functions that make compiler execute code for you, such as eval(), exec() or similar.

This is a Community Wiki, meaning neither the question nor answers get the reputation points from votes. But vote anyway!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

稚气少女 2024-08-02 10:15:35

Python,250 字节。

这个比 ilya n. 的 Python 解决方案更长,但该语言更容易掌握。 这种语言中的每个命令(我称之为 Kaputt,德语中的“损坏”一词)都是一个字节。 定义了以下 6 个命令:

  • 0:将 0 压入堆栈
  • 1:将 1 压入堆栈
  • I:(if) Pop堆栈外的值(必须为零或一)。 如果是 1,则运行以下代码块(直到“i”); 如果该块为零,则跳过该块。
  • i:(endif) 如果该块运行,则结束 if 块并推送 1(因为“I”弹出零) 。 请参阅下文了解后者的解释。
  • D:(def) 将要定义的函数的名称从堆栈中弹出(见下文),并将以下块(直到“d”)绑定到该函数姓名。
  • d: (enddef) 结束函数定义。
  • 任何其他字节:检查此(一个字节;但请参阅下面的编辑)名称是否有函数。 如果是,则运行该函数; 如果没有,则将此字节压入堆栈以供 D 立即使用。

嵌套 if 是合法的; 嵌套函数定义不是。 事实上,当且仅当相应的 if 块未运行时,i (endif) 才会推送 1,这一事实允许使用以下类似于 if/else/endif 结构的习惯用法:

# [code that left a one or zero on the stack]
I    # abbreviated "(" below
# [code to be run if it was a one]
0iI  # abbreviated "/" below
# [code to be run if it was a zero]
1iIi # abbreviated ")" below
# [continuing...]

请注意注释、换行符、空格等实际上是不允许的。

以下是一些常见功能的示例。 这些使用了上面提到的缩写( / )

<D(/)d

定义函数 < (pop),该函数从堆栈中弹出一个值,而不将其用于任何用途。

&D((1/0)/<0)d

定义函数 & (和),该函数弹出堆栈中的两个值,如果两个值都是 1,则压入 1,否则压入 0。

~D((11/10)/(01/00))d

定义交换堆栈顶部两个值的函数 ~ (swap)。

RD(R/<)d

定义函数R(删除),该函数递归地从堆栈顶部删除所有值,然后再删除两个值(其中顶部的值应为零)。

以下解释器函数需要程序 p,它是一个字符串(或任何其他可迭代的字节),以及输入堆栈 S,它是一个(可能为空)字节列表。 解释器运行后,此列表包含输出堆栈。

def i(p,S,F=0):
 A=S.append
 F=F or{}
 C=0
 k=[]
 for c in p:
  h=0in k
  if c=="d":C=0
  elif C!=0:C+=[c]
  elif c=="I":k+=[int(h or S.pop())]
  elif c=="i":k.pop()or A("1")
  elif 1-h:
   if c=="D":C=F[S.pop()]=[]
   else:i(F.get(c)or A(c)or"",S,F)

显然,没有空间进行错误检查,因此 i() 需要合法的 Kaputt 代码。 测试用例:

script = "<D(/)d"                 # < = pop
script += "&D((1/0)/<0)d"         # & = and
script += "~D((11/10)/(01/00))d"  # ~ = swap
script += "RD(R/<)d"              # R = remove
script += "|D(<1/(1/0))d"         # | = or
script=script.replace("(","I")   
script=script.replace("/","0iI")
script=script.replace(")","1iIi") # ( and / and ) are no real commands of the language.

S=[]
i(script+"1111010111111111R",S)
assert S == ["1","1","1","1","0"]

S=[]
i(script+"00&",S)
assert S == ["0"]

S=[]
i(script+"01~",S)
assert S == ["1","0"]

S=[]
i(script+"00|",S)
assert S == ["0"]

S=[]
i(script+"01|",S)
assert S == ["1"]

快乐编码:-)

编辑:解释器中没有任何固有的东西强制令牌仅是一个字节。 要求这一点更多是为了与内置命令(这些命令是单字节的,因为这使得解释器更短)保持一致。 如果您传递字符串列表而不是字符串,则可以编写更易读的 Kaputt 代码,如下所示:

script = """
inc D
    (
        (
            0 0
        /
            1 0
        )
    /
        1
    )
d
""".replace("(","I").replace("/","0 i I").replace(")","1 i I i").split()

这定义了一个函数 inc ,该函数递增顶部的两位数字堆栈(LSB 在顶部)。

测试:

for n in xrange(4):
    S=[]
    i(script + [str((n & 2)/2), str(n & 1), "inc"], S)
    assert S == [str(((n+1) & 2)/2), str((n+1) & 1)]

让我们将多字节函数名称称为语言扩展:-)

Python, 250 bytes.

This one is longer than ilya n.'s Python solution, but the language is a little easier to grasp. Each command in this language (I call it Kaputt, the German word for "broken") is one byte. The following 6 commands are defined:

  • 0: Push a zero onto the stack
  • 1: Push a one onto the stack
  • I: (if) Pop a value off the stack (which must be zero or one). Run the following block of code (until "i") if it's a one; skip the block if it's a zero.
  • i: (endif) Ends the if block and pushes a one if the block was not run (because the "I" popped a zero). See below for an explanation of the latter.
  • D: (def) Pops the name of the to-be-defined function off the stack (see below) and binds the following block (until "d") to that name.
  • d: (enddef) Ends the function definition.
  • Any other byte: Check if there is a function by this (one-byte; but see the edit below) name. If so, run this function; if not, push this byte onto the stack for immediate use by D.

Nested ifs are legal; nested function definitions are not. The fact that i (endif) pushes a one if and only if the corresponding if block was not run allows for the following idiom resembling an if/else/endif structure:

# [code that left a one or zero on the stack]
I    # abbreviated "(" below
# [code to be run if it was a one]
0iI  # abbreviated "/" below
# [code to be run if it was a zero]
1iIi # abbreviated ")" below
# [continuing...]

Note that comments, linebreaks, spaces etc. are not actually allowed.

Here are some examples of common functions. These make use of the abbreviations ( / ) mentioned above.

<D(/)d

defines the function < (pop) that pops a value off the stack without using it for anything.

&D((1/0)/<0)d

defines the function & (and) that pops two values of the stack and pushes a one if both values are ones, pushes a zero otherwise.

~D((11/10)/(01/00))d

defines the function ~ (swap) that swaps the top two values on the stack.

RD(R/<)d

defines the function R (remove) that recursively removes all ones from the top of the stack, and then removes two more values (the top one of which should be zero).

The following interpreter function expects the program p, which is a string (or any other iterable of bytes), and the input stack S, which is a (possibly empty) list of bytes. After the interpreter has run, this list contains the output stack.

def i(p,S,F=0):
 A=S.append
 F=F or{}
 C=0
 k=[]
 for c in p:
  h=0in k
  if c=="d":C=0
  elif C!=0:C+=[c]
  elif c=="I":k+=[int(h or S.pop())]
  elif c=="i":k.pop()or A("1")
  elif 1-h:
   if c=="D":C=F[S.pop()]=[]
   else:i(F.get(c)or A(c)or"",S,F)

Obviously, there was no room for error checking, so i() expects legal Kaputt code. Test cases:

script = "<D(/)d"                 # < = pop
script += "&D((1/0)/<0)d"         # & = and
script += "~D((11/10)/(01/00))d"  # ~ = swap
script += "RD(R/<)d"              # R = remove
script += "|D(<1/(1/0))d"         # | = or
script=script.replace("(","I")   
script=script.replace("/","0iI")
script=script.replace(")","1iIi") # ( and / and ) are no real commands of the language.

S=[]
i(script+"1111010111111111R",S)
assert S == ["1","1","1","1","0"]

S=[]
i(script+"00&",S)
assert S == ["0"]

S=[]
i(script+"01~",S)
assert S == ["1","0"]

S=[]
i(script+"00|",S)
assert S == ["0"]

S=[]
i(script+"01|",S)
assert S == ["1"]

Happy coding :-)

Edit: There is nothing inherent in the interpreter that forces tokens to be one byte only. Requiring this was more for consistency with the built-in commands (which are one-byte because that makes the interpreter shorter). If you pass a list of strings instead of a string, you can write more readable Kaputt code like this:

script = """
inc D
    (
        (
            0 0
        /
            1 0
        )
    /
        1
    )
d
""".replace("(","I").replace("/","0 i I").replace(")","1 i I i").split()

This defines a function inc that increments the two-bit number on top of the stack (LSB on top).

Test:

for n in xrange(4):
    S=[]
    i(script + [str((n & 2)/2), str(n & 1), "inc"], S)
    assert S == [str(((n+1) & 2)/2), str((n+1) & 1)]

Let's call multi-byte function names a language extension :-)

套路撩心 2024-08-02 10:15:35

解释我刚刚创建的语言的Python程序:

from random import randint
z = [randint(0,1), None]  # example: input data is 0 or 1
x = '_b_ed_a_i____d_ai'   # this program will set p = data[1] = not data[0]

# input x[i], data z[k]
# jumper j
# p is +1 or -1 each step
# commands:
#    a   set data = 0 or 1
#    b   j += 0 or +-9 depending on data
#    d   move data left or right
#    e   perform jump left or right
#    j   set jumper to 0
#    i   end program
# output: p or some data[x], both possible

g = globals()
p = i = 1
a = b = d = j = e = k = 0
while i:
    h = x[i]
    g[h] = p = -p
    i += 1 + j*e
    if a: z[k] = i % 2
    if z[k]: j += 9*b
    k += d
    g[h] = 0        
#    print(a, b, d, e, i, j, k, h, z)

print('Input:', z, 'Output:', p > 0)

优化版本:

g=globals()
p=i=1
a=b=d=j=e=k=0
while i:
 h=x[i]
 g[h]=p=-p
 i+=1+j*e
 if a:z[k]=i%2
 if z[k]:j+=9*b
 k+=d
 g[h]=0

114字节

更新:我想补充一点,我的程序的目的不是创建任何实用的语言,并且甚至不是为了以某种方式拥有“最好的”(==“最短的”)解释器,而是为了演示有趣的编程技巧。 例如,我依赖于通过 globals() 直接访问全局变量,因此我什至从未测试过 j 命令,从而节省了宝贵的字节:)

Python program that interprets a language I just created:

from random import randint
z = [randint(0,1), None]  # example: input data is 0 or 1
x = '_b_ed_a_i____d_ai'   # this program will set p = data[1] = not data[0]

# input x[i], data z[k]
# jumper j
# p is +1 or -1 each step
# commands:
#    a   set data = 0 or 1
#    b   j += 0 or +-9 depending on data
#    d   move data left or right
#    e   perform jump left or right
#    j   set jumper to 0
#    i   end program
# output: p or some data[x], both possible

g = globals()
p = i = 1
a = b = d = j = e = k = 0
while i:
    h = x[i]
    g[h] = p = -p
    i += 1 + j*e
    if a: z[k] = i % 2
    if z[k]: j += 9*b
    k += d
    g[h] = 0        
#    print(a, b, d, e, i, j, k, h, z)

print('Input:', z, 'Output:', p > 0)

Optimized version:

g=globals()
p=i=1
a=b=d=j=e=k=0
while i:
 h=x[i]
 g[h]=p=-p
 i+=1+j*e
 if a:z[k]=i%2
 if z[k]:j+=9*b
 k+=d
 g[h]=0

114 bytes

Update: I want to add that the point of my program is not to create any practical language, and not even to somehow have the 'best' (=='shortest') interpreter, but rather to demonstrate interesting programming tricks. For example, I am relying on direct access to global variables through globals(), so that I never even test for j command, saving precious bytes :)

甜味拾荒者 2024-08-02 10:15:35
#include "/dev/tty"
#include "/dev/tty"
月寒剑心 2024-08-02 10:15:35

使用 A86 组装下面的代码即可获得 150 字节的 BF 解释器!

    add dh,10h
    push dx
    add dh,10h
    push dx
    mov bl,80h
    lea dx,[bx+2]
    add bl,byte ptr [bx]
    mov byte ptr [bx+1],al
    mov ah,3dh
    int 21h
    pop ds,es
    jc l14
    mov bx,ax
    mov ah,3fh  
    mov cx,di
    xor dx,dx
    int 21h
    jc l14
    mov bx,ax
    xor ax,ax
    rep stosw
    xor di,di
    xor si,si
    inc ch
l1:
    cmp si,bx
    jae l14
    lodsb
    mov bp,8
    push l1
l2: 
    dec bp
    js ret
    cmp al,[bp+l15]
    jne l2
l3:
    mov cl,[bp+8+l15]
    jmp cx
l4:
    inc di  
    ret
l5:
    dec di
    ret
l6:
    es inc byte ptr [di]
    ret
l7:
    es dec byte ptr [di]
    ret
l8:
    mov ah,2
    es mov dl,[di]
    int 21h
    ret
l9:
    mov ah,8
    int 21h
    es mov [di],al
    ret
l10:
    es cmp byte ptr [di],dh
    jne ret
l11:    
    cmp si,bx
    jae l14
    lodsb
    cmp al,']'
    jne l11
    ret
l12:
    es cmp byte ptr [di],dh
    je ret
l13:    
    dec si
    jz l14
    cmp byte ptr [si-1],'['
    jne l13
l14:
    ret
l15:
    db '>'
    db '<'
    db '+'
    db '-'
    db '.'
    db ','
    db '['
    db ']'
    db offset l4-100h
    db offset l5-100h
    db offset l6-100h
    db offset l7-100h
    db offset l8-100h
    db offset l9-100h
    db offset l10-100h
    db offset l12-100h

在命令行指定一个文件名,不需要双引号,作为BF源。

Assemble the code below using A86 to get a 150 byte BF interpreter!

    add dh,10h
    push dx
    add dh,10h
    push dx
    mov bl,80h
    lea dx,[bx+2]
    add bl,byte ptr [bx]
    mov byte ptr [bx+1],al
    mov ah,3dh
    int 21h
    pop ds,es
    jc l14
    mov bx,ax
    mov ah,3fh  
    mov cx,di
    xor dx,dx
    int 21h
    jc l14
    mov bx,ax
    xor ax,ax
    rep stosw
    xor di,di
    xor si,si
    inc ch
l1:
    cmp si,bx
    jae l14
    lodsb
    mov bp,8
    push l1
l2: 
    dec bp
    js ret
    cmp al,[bp+l15]
    jne l2
l3:
    mov cl,[bp+8+l15]
    jmp cx
l4:
    inc di  
    ret
l5:
    dec di
    ret
l6:
    es inc byte ptr [di]
    ret
l7:
    es dec byte ptr [di]
    ret
l8:
    mov ah,2
    es mov dl,[di]
    int 21h
    ret
l9:
    mov ah,8
    int 21h
    es mov [di],al
    ret
l10:
    es cmp byte ptr [di],dh
    jne ret
l11:    
    cmp si,bx
    jae l14
    lodsb
    cmp al,']'
    jne l11
    ret
l12:
    es cmp byte ptr [di],dh
    je ret
l13:    
    dec si
    jz l14
    cmp byte ptr [si-1],'['
    jne l13
l14:
    ret
l15:
    db '>'
    db '<'
    db '+'
    db '-'
    db '.'
    db ','
    db '['
    db ']'
    db offset l4-100h
    db offset l5-100h
    db offset l6-100h
    db offset l7-100h
    db offset l8-100h
    db offset l9-100h
    db offset l10-100h
    db offset l12-100h

Specify a filename on the command line, no need for double quotes, as the BF source.

苏别ゝ 2024-08-02 10:15:35

不是我的,但是看看 210 位二进制 lambda 演算自解释器 此处

Not mine, but take a look at the 210 bit binary lambda calculus self-interpreter here.

_畞蕅 2024-08-02 10:15:35

Perl 编写,长 140 个字符,包括 shell 调用和标志:

perl -ne'push@a,split;if(eof){$i=0;while($i>=0){($a,$b,$c)=@a[$i..$i+2];$b>-1?$a[$b]-=$a[$a]:print chr$a[$a];$i=$b>-1&&$a[$b]<=0?$c:$i+3;}}'

可读版本:

#!/usr/bin/perl -n
push @prog, split /\s+/, $_;
if(eof) {
  $i = 0;
  while($i >= 0) {
    ($a, $b, $c) = @prog[$i .. $i + 2];
    if($b > -1) {
      $prog[$b] -= $prog[$a];
    } else {
      print chr $prog[$a];
    }
    if($b > -1 and $prog[$b] <= 0) {
      $i = $c;
    } else {
      $i + 3;
    }
  }
}

上面是 使用 subleq 指令的一个指令集计算机。 基本上,源代码应该只是一堆用空格分隔的数字。 一个简单的测试程序来验证我的结果(应该打印“Hi”和 Unix 换行符):

0 0 6 72 105 10 3 -1 9 4 -1 12 5 -1 15 0 0 -1

测试输入的可读版本(同样有效):

0    0     6
72   105   10
3   -1     9
4   -1     12
5   -1     15
0    0    -1

Written in Perl, 140 characters long, including the shell invocation and flags:

perl -ne'push@a,split;if(eof){$i=0;while($i>=0){($a,$b,$c)=@a[$i..$i+2];$b>-1?$a[$b]-=$a[$a]:print chr$a[$a];$i=$b>-1&&$a[$b]<=0?$c:$i+3;}}'

Readable version:

#!/usr/bin/perl -n
push @prog, split /\s+/, $_;
if(eof) {
  $i = 0;
  while($i >= 0) {
    ($a, $b, $c) = @prog[$i .. $i + 2];
    if($b > -1) {
      $prog[$b] -= $prog[$a];
    } else {
      print chr $prog[$a];
    }
    if($b > -1 and $prog[$b] <= 0) {
      $i = $c;
    } else {
      $i + 3;
    }
  }
}

The above is an interpreter for pseudo-machine code for a One Instruction Set Computer using the subleq instruction. Basically, the source code should just be a bunch of numbers separated by whitespace. A simple test program to verify my results (should print "Hi" and a Unix newline):

0 0 6 72 105 10 3 -1 9 4 -1 12 5 -1 15 0 0 -1

Readable version of the test input (works just as well):

0    0     6
72   105   10
3   -1     9
4   -1     12
5   -1     15
0    0    -1
灯角 2024-08-02 10:15:35

我自己的条目,在 OISC -lang.org/" rel="nofollow noreferrer">Ruby。 它有 85 个字节长,我确信可以通过一些巧妙的技巧来压缩更多字节。 程序必须在代码中包含数据(以空格分隔的数字行)。 目前我无法提供用 OISC 编写的工作程序,但我稍后会提供。

p,m=0,gets.chomp.split.map(:to_i)
while p>0
p=(m[m[b]]-=m[m[a]])>0?p+3:c
end
gt;<<m[0]

代码相当简单。 m 是包含程序和数据的“存储器”。 第一行使用提供的代码初始化 mp - 内存指针。 主循环是subleq操作,用三元运算符编写。 最后一行是输出内存中包含的数字的智能方式。

My own entry, implementation of OISC in Ruby. It's 85 bytes long, and I'm sure one could squeeze a few more with some neat tricks. Programs have to contain data in code (line of space-separated numbers). At the moment I'm unable to provide working program written in OISC, but I will do it later.

p,m=0,gets.chomp.split.map(:to_i)
while p>0
p=(m[m[b]]-=m[m[a]])>0?p+3:c
end
gt;<<m[0]

The code is quite straightforward. m is a "memory" containing program and data. First line initializes m with provided code, and p - memory pointer. Main loop is subleq operation, written with ternary operator. Last line is smart way to output number contained in memory.

七色彩虹 2024-08-02 10:15:35

我之前的代码高尔夫条目为基础,这里有一个(稍微IO 通用) OISC

Fortran77

中的仿真器已混淆并且没有加载支架(655 个字符):

  subroutine o(n,m)
  integer m(n)              
  l=1;                      
  do while (l.ne.0)
     i=m(l)
     j=m(l+1)
     k=m(l+2)
     mi=mg(n,m,i)
     mj=mg(n,m,j)
     if(j.eq.(n+2)) then
        write(6,*)mj-mi
     else
        m(l+1)=mj-mi
     endif
     if (m(l+1).lt.0) then
        l=mg(n,m,k)
     else
        l=l+3
     endif
  end do
  return
  end
  function mg(n,m,i)
  integer m(n)
  if (i.eq.n+2) then
     read(5,*)mg
  elseif (i.eq.n+1) then
     mg=0
  else
     mg=m(i)
  endif
  return
  end

带有注释,加载脚手架等(2435个字符):

      program c
      parameter (n=1024)        ! The size to use for memeory
      integer m(n)              ! represent the memory
c     Load a program into memory
      i=1
 1    read(5,*,end=2)l
c     write (6,*) "Load ",l," into location ",i
      m(i)=l
      i=i+1
      goto 1
c     Run the computer
 2    call o(n,m)
      stop
      end

      subroutine o(n,m)
c     Simulate a simple computer that supports only a single
c     instruction. Memory is a fixed size array of integers.
c
c     The supported instruction is subtract-branch-negative which we
c     give the assembly syntax
c
c     sbn i j k
c
c     and acts by subtracting the value in memeory location i from that
c     in location j and storing the result in j. If the result is
c     negative, the PC is set to k. Because there is only one opcode, it
c     is not represented, so a program consists simply of a series of
c     triplet (i,j,k), and the PC is generally incremented by 3. The
c     program counter starts at 1
c
c     Povisions for IO and halting are by way of special memory
c     location:
c
c     * PC=0 means halt
c     * writes (opcode argument j) to memory location n+1 send
c       output, reads from n+1 evaluate as 0
c     * reads (opcode argument i, j, k) from memory location n+2 fetch
c       input, writes to n+2 are forbidden
c     * All others reads and writes outside of memeory are forbidden

c     n                         ! the size of the computers memory 
      integer m(n)              ! an array representing the computers memory
      l=1;                      ! program counter
      do while (l.ne.0)
         i=m(l)
         j=m(l+1)
         k=m(l+2)
c        write (6,*) "Executing from PC=",l,": (",i,", ",j,", ", k,")"
c        handle the write special case for output
         mi=mg(n,m,i)
         mj=mg(n,m,j)
         if(j.eq.(n+1)) then
            write(6,*)mj-mi
         else
c           write (6,*) "Setting location ",j," to ",mj-mi
            m(l+1)=mj-mi
         endif
         if (m(l+1).lt.0) then
            l=mg(n,m,k)
         else
            l=l+3
         endif
      end do
      return
      end

c     Handle the various read special cases
      function mg(n,m,i)
      integer m(n)
      if (i.eq.n+2) then
         read(5,*)mg
      elseif (i.eq.n+1) then
         mg=0
      else
         mg=m(i)
      endif
c     write (6,*) "Read ",mg," from location ",i
      return
      end

示例程序:

13
1025
0

14 
1025
0

14
15
0

0
0
0

-1
1
0

产生输出:

$ cat trivial.oisc | ./a.out 
           1
          -1

符合预期。

这确实是非常简单的代码。 这里的重点并不是我可以将其编码得有多严格,而是图灵完整性所需的语言有多简单。

Building on my previous code-golf entry, here is a (slightly generalized for IO) OISC emulator in

Fortran77

Obsfucated and without the loading scaffold (655 characters):

  subroutine o(n,m)
  integer m(n)              
  l=1;                      
  do while (l.ne.0)
     i=m(l)
     j=m(l+1)
     k=m(l+2)
     mi=mg(n,m,i)
     mj=mg(n,m,j)
     if(j.eq.(n+2)) then
        write(6,*)mj-mi
     else
        m(l+1)=mj-mi
     endif
     if (m(l+1).lt.0) then
        l=mg(n,m,k)
     else
        l=l+3
     endif
  end do
  return
  end
  function mg(n,m,i)
  integer m(n)
  if (i.eq.n+2) then
     read(5,*)mg
  elseif (i.eq.n+1) then
     mg=0
  else
     mg=m(i)
  endif
  return
  end

with comments, loading scaffold and so on (2435 characters):

      program c
      parameter (n=1024)        ! The size to use for memeory
      integer m(n)              ! represent the memory
c     Load a program into memory
      i=1
 1    read(5,*,end=2)l
c     write (6,*) "Load ",l," into location ",i
      m(i)=l
      i=i+1
      goto 1
c     Run the computer
 2    call o(n,m)
      stop
      end

      subroutine o(n,m)
c     Simulate a simple computer that supports only a single
c     instruction. Memory is a fixed size array of integers.
c
c     The supported instruction is subtract-branch-negative which we
c     give the assembly syntax
c
c     sbn i j k
c
c     and acts by subtracting the value in memeory location i from that
c     in location j and storing the result in j. If the result is
c     negative, the PC is set to k. Because there is only one opcode, it
c     is not represented, so a program consists simply of a series of
c     triplet (i,j,k), and the PC is generally incremented by 3. The
c     program counter starts at 1
c
c     Povisions for IO and halting are by way of special memory
c     location:
c
c     * PC=0 means halt
c     * writes (opcode argument j) to memory location n+1 send
c       output, reads from n+1 evaluate as 0
c     * reads (opcode argument i, j, k) from memory location n+2 fetch
c       input, writes to n+2 are forbidden
c     * All others reads and writes outside of memeory are forbidden

c     n                         ! the size of the computers memory 
      integer m(n)              ! an array representing the computers memory
      l=1;                      ! program counter
      do while (l.ne.0)
         i=m(l)
         j=m(l+1)
         k=m(l+2)
c        write (6,*) "Executing from PC=",l,": (",i,", ",j,", ", k,")"
c        handle the write special case for output
         mi=mg(n,m,i)
         mj=mg(n,m,j)
         if(j.eq.(n+1)) then
            write(6,*)mj-mi
         else
c           write (6,*) "Setting location ",j," to ",mj-mi
            m(l+1)=mj-mi
         endif
         if (m(l+1).lt.0) then
            l=mg(n,m,k)
         else
            l=l+3
         endif
      end do
      return
      end

c     Handle the various read special cases
      function mg(n,m,i)
      integer m(n)
      if (i.eq.n+2) then
         read(5,*)mg
      elseif (i.eq.n+1) then
         mg=0
      else
         mg=m(i)
      endif
c     write (6,*) "Read ",mg," from location ",i
      return
      end

Sample program:

13
1025
0

14 
1025
0

14
15
0

0
0
0

-1
1
0

resulting in output:

$ cat trivial.oisc | ./a.out 
           1
          -1

which is as expected.

It really is exceedingly straightforward code. The point here is not really how tightly I can code it, but how simple a language you need for Turing completeness.

梦年海沫深 2024-08-02 10:15:35

106 字节解决方案 已发布到 codegolf.com 竞赛。 它是用 Perl 编写的,并解释 Brainfuck。 目前还没有办法对其进行审查,afaik。

这不是我的解决方案,但我相信它比当前条目短。 可能的解决方案应该更短,因为不需要使用 Brainfuck 作为图灵完备的语言。

106-byte solution was posted to codegolf.com contest. It is written in perl and interprets Brainfuck. There is no way to review it at this point, afaik.

It is not my solution, but I believe it is shorter than current entries. Possible solution should be shorter, as there is no need to use Brainfuck as Turing-complete language.

等待我真够勒 2024-08-02 10:15:35

URM 解释器位于 CoffeeScript143 字节(167 个新行)。

此版本的 URM 由无限数量的寄存器组成,其中包括零、后继和跳转运算符。 众所周知,这是图灵完备的。

URM 程序写入数组c(命令)中,输入位于数组r(寄存器)中。 计算后,输出位于 r[0] 处并显示该值。

解释器,带有示例程序和计算 32+13 的输入(实际上输出 45):

# Addition program, similar to http://planetmath.org/examplesofunlimitedregistermachines
c = [['j', 1, 2, 4], ['s', 0], ['s', 2], ['j', 1, 1, 0]]

# Input: 32, 13, thus the desired output is: 45
r = [32, 13]

k = 0
while k < c.length
    t = c[k]
    k += 1
    if t[0] == 'z'
        r[t[1]] = 0
    if t[0] == 's'
        if !r[t[1]]?
            r[t[1]] = 0
        r[t[1]] += 1
    if t[0] == 'j' && r[t[1]] == r[t[2]]
        k = t[3]
alert r[0]

缩小版本:

k=0
while k<c.length
 t=c[k]
 k+=1
 if t[0]=='z'
  r[t[1]]=0
 if t[0]=='s'
  if !r[t[1]]?
   r[t[1]]=0
  r[t[1]]+=1
 if t[0]=='j'&&r[t[1]]==r[t[2]]
  k=t[3]
alert r[0]

我真正喜欢这段代码的是它非常简单且易于理解。

URM interpreter in CoffeeScript, 143 bytes (167 with new lines).

This version of URM has consists of an unbounded amount of registers, with zero, successor and jump operators. It is well known that this is turing-complete.

The URM program is written in the array c (commands), and the inputs are in the array r (registers). After the calculation the output is at r[0] and this value is displayed.

The interpreter, with sample program and input that computes 32+13 (and indeed outputs 45):

# Addition program, similar to http://planetmath.org/examplesofunlimitedregistermachines
c = [['j', 1, 2, 4], ['s', 0], ['s', 2], ['j', 1, 1, 0]]

# Input: 32, 13, thus the desired output is: 45
r = [32, 13]

k = 0
while k < c.length
    t = c[k]
    k += 1
    if t[0] == 'z'
        r[t[1]] = 0
    if t[0] == 's'
        if !r[t[1]]?
            r[t[1]] = 0
        r[t[1]] += 1
    if t[0] == 'j' && r[t[1]] == r[t[2]]
        k = t[3]
alert r[0]

Minified version:

k=0
while k<c.length
 t=c[k]
 k+=1
 if t[0]=='z'
  r[t[1]]=0
 if t[0]=='s'
  if !r[t[1]]?
   r[t[1]]=0
  r[t[1]]+=1
 if t[0]=='j'&&r[t[1]]==r[t[2]]
  k=t[3]
alert r[0]

What I really like in this code is that is really straightforward and easy to understand.

那伤。 2024-08-02 10:15:35

自定义语言:SLA
关键字:
i - 解释 SLB
q - 退出

自定义语言:SLB
关键字:
cp("text") - 将文本解释为 C 程序

示例:
cp("#include \nint main() { put(\"Hi!\n\");return 0}")

解释器(用 SLA 编写):
i q

3 个字符!

Custom language: SLA
Keywords:
i - Interpret SLB
q - Quit

Custom Language: SLB
Keywords:
cp("text") - Interpret text as C program

Example:
cp("#include \nint main() { puts(\"Hi!\n\");return 0}")

Interpreter (Written in SLA):
i q

3 characters!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文