HackThisSite - ExtBasic Mission 03

Challenge

playit 型关卡,题面给出一段用作者自造语言写的 5 行程序,要求给出它的输出:

1
2
3
4
5
BEGIN notr.eal
CREATE int AS 2
DESTROY int AS 0
ANS var AS Create + TO
out TO

Solution

  • BEGIN notr.eal 只是程序头,notr.eal 读作 not real,这门语言本身是虚构的,没有任何公开语法可查。

  • CREATEDESTROYANSTO 在这个语言里都只是普通标识符,是一组自指单词;它们的字面含义(创建 / 销毁 / 答案 / 到)是纯粹的误导。

  • 真正起作用的语法骨架只有三点:<标识符> <类型> AS <表达式> 做声明赋值、+ 做整数加法、out 做输出。

  • AS 是赋值分隔符,int / var 只是类型标注,不参与数值。

  • CREATE int AS 2:把 2 绑定到标识符 CREATE

  • DESTROY int AS 0:把 0 绑定到标识符 DESTROY

  • ANS var AS Create + TO:计算 Create + TO。标识符归一化后 Create 就是第 2 行的 CREATE(值为 2),TO 从未被赋值、按未绑定标识符计 0,所以 ANS = 2 + 0 = 2

  • out TOout 是输出语句,行尾的 TO 指出输出通道而不是变量,打印当前答案。

把上面的规则写成一个最小解释器,复现整条数值流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import re

PROGRAM = "\n".join([
"BEGIN notr.eal",
"CREATE int AS 2",
"DESTROY int AS 0",
"ANS var AS Create + TO",
"out TO",
])

def value_of(expr, env):
total = 0
for term in expr.split("+"):
term = term.strip()
if re.fullmatch(r"\d+", term):
total += int(term)
else:
total += env.get(term.lower(), 0)
return total

def run(source):
env = {}
answer = None
for line in source.splitlines():
parts = line.split()
if not parts or parts[0] == "BEGIN":
continue
if parts[0] == "out":
print("out %s -> %s" % (parts[1], answer))
continue
name, declared_type, _as = parts[0], parts[1], parts[2]
expr = " ".join(parts[3:])
answer = value_of(expr, env)
env[name.lower()] = answer
print("%-8s %-4s AS %-14s => %d" % (name, declared_type, expr, answer))
return answer

if __name__ == "__main__":
print(run(PROGRAM))

运行输出

1
2
3
4
5
CREATE   int  AS 2              => 2
DESTROY int AS 0 => 0
ANS var AS Create + TO => 2
out TO -> 2
2