构建一个 Human Resource Machine 编译器 - 语言设计
构建一个 Human Resource Machine 编译器 - 语言设计
(Thanks to Doubao for translating. See original at this page. 感谢豆包的翻译, 原文见此页面。如有差异,请以英文版为准。如果中文使你困惑看不懂,也请读英文版。)
这是Human Resource Machine 编译器系列的一篇文章。
现在,我们需要确定这种语言真正需要的是什么。这个游戏的机制相当简单,所使用的处理器也非常基础。我们将从关注游戏的早期关卡开始,随着我们进入后期关卡,逐渐扩展我们的语言。这种语言在达到第 20 年关卡之前都是有效的,而我目前就在这个关卡,并且看起来不需要太多脑力就能达到这一点。
在游戏中,我们的任务是执行各种操作,所以看起来我们将设计一种命令式语言。目前,游戏只能处理一种数据类型——整数。为了支持逻辑操作,我们还定义了一个布尔类型。我们需要实现算术和逻辑操作,但目前位操作不是必需的。对于这些操作,我们将遵循 C 语言中的优先级和结合性规则。是否以短路方式评估表达式可以稍后决定。
我们引入基本操作:
- 算术
+
,加法-
,减法*
,乘法/
,整数除法%
,取模++
,自增--
,自减
- 逻辑
&&
,与||
,或>
,大于>=
,大于等于<
,小于<=
,小于等于==
,等于!=
,不等于!
,非
运算符优先级和结合性定义如下。
优先级 | 运算符 | 描述 | 结合性 |
---|---|---|---|
12 | a() | 函数调用 | 从左到右 → |
11 | floor[] | 访问地板 | 从左到右 → |
10 | ++a --a | 前缀自增和自减 | 从右到左 ← |
9 | +a -a | 一元加和一元减 | 从右到左 ← |
8 | ! | 逻辑非 | 从右到左 ← |
7 | a*b a/b a%b | 乘法、除法和取余 | 从左到右 → |
6 | a+b a-b | 加法和减法 | 从左到右 → |
5 | < <= > >= | 关系运算符 | 从左到右 → |
4 | == != | 相等运算符 | 从左到右 → |
3 | && | 逻辑与 | 从左到右 → |
2 | ` | ` | |
1 | = | 直接赋值 | 从右到左 ← |
变量可以用与其他语言类似的作用域来定义。我们支持全局、函数和块级作用域。在这种语言中,不允许变量遮蔽,这意味着如果一个变量已经在外部作用域中定义,就不能在一个块中重新定义它。我们也跳过了static
变量,因为它们似乎不是必需的。
这种语言没有很强的类型概念——我们处理的都是整数。虽然我们可能会使用布尔值,但它们很容易用整数表示。作为一种语法糖,我们定义了true
和false
,它们在内部将被视为 1 和 0。与 C 语言类似,在逻辑操作中,任何非零值都被视为true
,而零被视为false
。
由于游戏没有栈或堆,我们的语言也不会有它们。相反,我们有一系列的存储单元(称为“地板”)。用户可以直接访问特定的地板值,而语言将自动管理其余的地板盒子。为了便于编译和优化,我们引入两个地板指令:init floor[IDX] = VAL
和init floor_max = VAL
。第一个指令告诉编译器某些地板盒子有预设值,而第二个指令指定地板上可用的最大槽位数。
鉴于游戏模仿了一个基本的处理器,我们将语言设计得接近非常低级的语言,但仍然能够处理常见的操作和逻辑。变量名是静态绑定的,不允许用户定义类型。游戏中需要基本的选择和循环结构,所以我们将它们包含在语言中。我们定义了一个while
循环(while (CONDITION) {}
)、一个for
循环(for (LOOP_VARIABLE_DECL, LOOP_CONDITION, LOOP_ADVANCEMENT) {}
)和一个if
语句(if (CONDITION) {} else {}
)。还为循环定义了continue
和break
。
最后是子程序。虽然游戏本身不支持子程序,但我们偶尔可能会需要它们。我们定义简化的子程序结构,只允许一个参数,使其更容易适应游戏的处理器。如果一个子程序有返回值,它应该是一个function
。否则,使用sub
(就像在 BASIC 中一样😄)。我们还定义了两个特殊的子程序,inbox()
和outbox(val)
,它们的作用与游戏中的相同。调用和返回的机制完全是由实现定义的。
最后一件事——模块。我们可能希望在不同关卡中设计通用的过程以供重用。我们引入import MODULE_NAME
。一个注意事项是,地板初始化指令在整个程序中只能出现一次,但这条规则可以在编译时强制执行。
这将是我们的极简“人力资源机器懒人编码语言”。以下是这种语言中的一个程序可能的样子:
import lang_mod;
// only single line comments allowed
init floor[1] = 1; // init floor[id] sets the initial value for a box on the floor
init floor[0] = 0;
init floor_max = 10;
// A function is defined, which takes an argument.
// Only one or zero argument is allowed.
function countdown(a) {
for (let i = a, i >= 0, --i) {
if (a % 2 == 0) {
continue;
}
outbox(i);
}
return a;
}
// sub marks a no-return function
sub no_return_func() {
// and it does nothing
}
// the program starts here
sub start() {
// a loop construct
// int(true) = 1, int(false) = 0, boolean and int are basically the same thing
// bool(1) = true, bool(0) = false, bool(anything except 0) = true
while (true) {
// inbox and outbox
let a = inbox();
let b = inbox();
if (a > b) {
outbox(a);
} else {
outbox(b);
}
let c = a * b;
let num = countdown(a);
floor[2] = num;
floor[3] = floor[b] + c;
outbox(c);
}
}