Python, 250字节。
这个比ilya n.的Python解决方案长一些,但语言更容易掌握。这种语言中的每个命令(我称其为 Kaputt,德语单词“broken”)都是一个字节。定义了以下6个命令:
0
: 将零压入堆栈1
: 将一压入堆栈I
: (if) 弹出堆栈上的值(必须为零或一)。如果是一,则运行以下代码块(直到"i
");如果是零,则跳过该块。i
: (endif) 结束 if 块,并在块未被运行时(因为 "I
" 弹出了零)将一推送到堆栈。有关后者的说明,请参见下文。D
: (def) 从堆栈中弹出要定义函数的名称(请参见下文),并绑定以下块(直到 "d
")以使用该名称。d
: (enddef) 结束函数定义。- 任何其他字节: 检查是否存在此(一个字节; 但请参见下面的编辑)名称的函数。如果是,则运行此函数;如果不是,则将此字节推送到堆栈上以供
D
立即使用。
嵌套的 ifs 是合法的; 嵌套的函数定义不可行。i
(endif) 仅在相应的 if 块未运行时推送一,这使得以下习惯用语类似于一个 if/else/endif 结构:
I
0iI
1iIi
请注意,注释、换行、空格等实际上是不被允许的。
以下是一些常见函数的示例。它们使用了前面提到的缩写符号( / )
。
<D(/)d
定义了函数<
(弹出),该函数从栈中弹出一个值,但不对其进行任何操作。
&D((1/0)/<0)d
定义了函数&
(与),它从堆栈中弹出两个值,并在这两个值都为1时推入1,在其他情况下推入0。
~D((11/10)/(01/00))d
该函数定义了~
(交换)函数,用于交换栈顶的两个值。
RD(R/<)d
定义了函数R
(删除),该函数递归地从栈顶删除所有的1,然后再删除两个值(其中顶部一个应为0)。
以下解释器函数期望程序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"
script += "&D((1/0)/<0)d"
script += "~D((11/10)/(01/00))d"
script += "RD(R/<)d"
script += "|D(<1/(1/0))d"
script=script.replace("(","I")
script=script.replace("/","0iI")
script=script.replace(")","1iIi")
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
的函数,它将栈顶上的两位数(最低有效位在上面)加一。
测试:
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)]
我们把多字节函数名称作语言扩展 :-)