コンパイラに取り組んでいるときに、名前付き引数リストと評価順序に関連する問題に直面しています。基本的に、言語は次の関数と関数呼び出しに対して次のことを保証します。
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
スタックの上位 2 つの要素を交換できる命令は 1 つしかないswap
ため、要素が増えると、コンパイラはローカル変数を生成する必要があります。
Actual: third second first
| | /¯¯¯¯
local0 swap local0
____/ | |
Formal: first second third
バイトコード:
third...
store local0
second...
first...
swap
load local0
call ...
もちろん、これは任意の量の実パラメータと形式パラメータに拡張できます。
私が今探しているのは、これらswap
またはローカル変数命令を挿入する必要があるかどうか、およびどこに挿入する必要があるかを決定するアルゴリズムです。コンパイラの実装への参照も役立ちます。
どの実引数がどの仮パラメータに属しているかは、私の問題の一部ではないことに注意してください。それは私のコンパイラによってすでに解決されています。簡単にするために、問題は次のように見ることができます。
同じ要素を異なる順序で含む同じサイズの 2 つの配列が与えられた場合、どの要素を最初の配列からスワップまたはシフトして、2 番目の配列の順序を取得できます。