形式主义有很多,因此尽管您可能会发现其他有用的资料,但我希望对此加以足够明确的说明,以免不必要。
RM由有限状态机和有限数量的命名寄存器组成,每个命名寄存器都包含一个非负整数。为了便于文本输入,此任务要求还命名状态。
状态分为三种:增量和减量,它们都引用一个特定的寄存器。然后终止 递增状态递增其寄存器并将控制权传递给其后继者。递减状态有两个后继者:如果其寄存器为非零,则递减状态并将控制权传递给第一个后继者;否则(即寄存器为零),它将控制权简单地传递给第二个后继者。
对于“ niceness”作为一种编程语言,终止状态需要打印一个硬编码的字符串(因此您可以指示异常终止)。
输入来自标准输入。输入格式包括每个状态一行,然后是初始寄存器内容。第一行是初始状态。状态行的BNF为:
line ::= inc_line
| dec_line
inc_line ::= label ' : ' reg_name ' + ' state_name
dec_line ::= label ' : ' reg_name ' - ' state_name ' ' state_name
state_name ::= label
| '"' message '"'
label ::= identifier
reg_name ::= identifier
标识符和消息的定义具有一定的灵活性。您的程序必须接受一个非空的字母数字字符串作为标识符,但是如果您愿意,它可以接受更通用的字符串(例如,如果您的语言支持带下划线的标识符,那么使用起来就更容易了)。同样,对于消息,您必须接受一个非空的字母数字和空格字符串,但是您可以接受更复杂的字符串,如果需要,可以使用转义的换行符和双引号字符。
输入的最后一行给出了初始寄存器的值,它是一个以空格分隔的ID = int分配列表,该列表必须为非空。不需要初始化程序中所有已命名的寄存器:未初始化的任何寄存器都假定为0。
您的程序应读取输入并模拟RM。当它到达终止状态时,它应该发出消息,换行符,然后发出所有寄存器的值(以任何方便,人类可读的格式和任何顺序)。
注意:形式上,寄存器应保存无界整数。但是,如果您希望假设没有寄存器的值会超过2 ^ 30。
一些简单的例子
a + = b,a = 0s0 : a - s1 "Ok"
s1 : b + s0
a=3 b=4
预期成绩:
Ok
a=0 b=7
b + = a,t = 0
init : t - init d0
d0 : a - d1 a0
d1 : b + d2
d2 : t + d0
a0 : t - a1 "Ok"
a1 : a + a0
a=3 b=4
预期成绩:
Ok
a=3 b=7 t=0
难以解析的机器的测试用例
s0 : t - s0 s1
s1 : t + "t is 1"
t=17
预期成绩:
t is 1
t=1
和
s0 : t - "t is nonzero" "t is zero"
t=1
预期成绩:
t is nonzero
t=0
一个更复杂的例子
摘自DailyWTF的Josephus问题代码挑战。输入是n(士兵人数)和k(前进),而r中的输出是幸存者的位置(零索引)。
init0 : k - init1 init3
init1 : r + init2
init2 : t + init0
init3 : t - init4 init5
init4 : k + init3
init5 : r - init6 "ERROR k is 0"
init6 : i + init7
init7 : n - loop0 "ERROR n is 0"
loop0 : n - loop1 "Ok"
loop1 : i + loop2
loop2 : k - loop3 loop5
loop3 : r + loop4
loop4 : t + loop2
loop5 : t - loop6 loop7
loop6 : k + loop5
loop7 : i - loop8 loopa
loop8 : r - loop9 loopc
loop9 : t + loop7
loopa : t - loopb loop7
loopb : i + loopa
loopc : t - loopd loopf
loopd : i + loope
loope : r + loopc
loopf : i + loop0
n=40 k=3
预期成绩:
Ok
i=40 k=3 n=0 r=27 t=0
该程序作为图片,对于那些视觉思考的人来说,发现掌握语法很有帮助:
如果您喜欢这种高尔夫,请看一下续集。