在编译器上工作时,我面临与命名参数列表和评估顺序相关的问题。基本上,该语言确保对于以下函数和函数调用:
int call(int first, int second) = first - second
int sideEffect(int i) { println(i); return i }
println(call(second: sideEffect(0), first: sideEffect(1)))
输出将是
0
1
1
尽管参数以相反的顺序给出。我正在研究 JVM,因此必须在字节码级别对它们进行排序以匹配call
. 在基于堆栈的伪字节码中:
push 0
call sideEffect(int)
push 1
call sideEffect(int)
swap
call call(int, int)
正如你所看到的,swap
这里需要一个字节码指令来确保它们都被评估并以正确的顺序传递。这可以绘制为图表:
Actual: second first
\ /
swap
/ \
Formal: first second
只有一条swap
指令可以交换堆栈顶部的两个元素,因此对于更多元素,编译器需要生成局部变量。
Actual: third second first
| | /¯¯¯¯
local0 swap local0
____/ | |
Formal: first second third
在字节码中:
third...
store local0
second...
first...
swap
load local0
call ...
当然,这可以扩展到任意数量的实际和形式参数。
我现在正在寻找的是某种算法,它确定我是否应该以及在哪里插入这些swap
或局部变量指令。对编译器实现的引用也会有所帮助。
请注意,哪个实际参数属于哪个形式参数不是我的问题的一部分。我的编译器已经解决了这个问题。为简化起见,可以这样看待问题:
给定两个大小相同的数组,其中包含不同顺序的相同元素,哪些元素可以从第一个数组交换或移动以获得第二个数组的顺序。