東北大学 工学研究科 電気・情報系 2016年3月実施 専門科目 問題5 計算機2
Author
祭音Myyura (co-authored with GPT 5.6 SOL)
Description
日本語版
Fig. 5(a) で定義したプログラミング言語および,Fig. 5(b) で定義したスタック機械の命令に関する以下の問に答えよ。スタック機械の各命令の動作は Fig. 5(c) で与えられている。空のスタックを [],空のスタックに n1,…,nk をこの順でプッシュしたときに得られるスタックの状態を [nk,…,n1] と書くことにする。
(1) 式 “(2−(3−5))” に対応する命令
PUSH 2; PUSH 3; PUSH 5; SUB; SUB; END
を考える。この命令を空のスタックから実行したときに得られるスタックの状態の遷移列を書き下せ。
(2) 式 “(ifz 3 then 4 else (5−6))” に対応する命令
PUSH 3; BRANCHZ (PUSH 4; END) (PUSH 5; PUSH 6; SUB; END)
を考える。この命令を空のスタックから実行したときに得られるスタックの状態の遷移列を書き下せ。
(3) 式 e を評価した結果が n であるとき,空のスタックから実行すると最終的なスタックの状態が [n] になるような命令 c が存在すれば,そのような c を compile(e) と書くことにする。命令 c1 と c2 に対し,命令 c1◃c2 を,c1 に出現する全ての END を c2 で置き換えることにより得られる命令であると定義する。たとえば,(PUSH 1; END) ◃ (PUSH 2; END) は PUSH 1; PUSH 2; END となる。また,たとえば compile((e1−e2)) は,もし compile(e1) と compile(e2) が存在すれば,compile(e1)◃compile(e2)◃(SUB; END) と表せる。演算子 ◃ は結合的であることに注意する。このとき以下の問に答えよ。
- (a) 整数定数式 n に対し,compile(n) を書き下せ。
- (b) e1,e2 および e3 を式とし,命令 compile(e1),compile(e2) および compile(e3) が存在すると仮定する。このとき compile((ifz e1 then e2 else e3)) を compile(e1),compile(e2),compile(e3) および ◃ を用いて表せ。また,命令
compile(((ifz 1 then 2 else 3)−4))
を具体的に書き下せ。計算の過程も示すこと。
- (c) 式 e の構文木のサイズに対し,compile(e) の構文木のサイズが指数関数的に大きくなる場合が存在するかを判定し,その根拠を示せ。
Fig. 5(a):式
e ::= n (整数定数)
| (e1 - e2) (整数減算)
| (ifz e1 then e2 else e3) (条件分岐)
ただし,式 “(ifz e1 then e2 else e3)” の値は,e1 の値が 0 と等しければ,e2 の値に,そうでなければ e3 の値に等しい。演算子 − は整数減算を表すとする。
Fig. 5(b):命令
c ::= END (命令の終端)
| PUSH n; c (整数プッシュ)
| SUB; c (整数減算)
| BRANCHZ (c1) (c2) (ゼロ分岐)
Fig. 5(c):各命令の動作
| 命令 | 動作 |
|---|
END | なにもしない(命令の終端)。 |
PUSH n; c | 整数 n をスタックにプッシュする。その後 c を実行する。 |
SUB; c | 2 つの整数 n2 と n1 をスタックからポップし,n1−n2 の結果をスタックにプッシュする。その後 c を実行する。ただし,n2 は最初のポップ操作で得られた整数であり,n1 は次のポップ操作で得られた整数である。 |
BRANCHZ (c1) (c2) | 整数 n をスタックからポップする。その後,n が 0 なら c1 を,そうでなければ c2 を実行する。 |
题目描述
表达式为整数 n、减法 e1−e2 或 ifz e1 then e2 else e3;条件值为零时取 e2,否则取 e3。
栈机指令如下,栈顶写在左边:
| 指令 | 行为 |
|---|
END | 结束 |
PUSH n; c | 压入 n,执行 c |
SUB; c | 先弹出 n2,再弹出 n1,压入 n1−n2,执行 c |
BRANCHZ (c1) (c2) | 弹出 n;n=0 执行 c1,否则执行 c2 |
- 从空栈执行
PUSH 2; PUSH 3; PUSH 5; SUB; SUB; END,写出栈变化。
- 从空栈执行
PUSH 3; BRANCHZ (PUSH 4; END) (PUSH 5; PUSH 6; SUB; END),写出栈变化。
- 令 compile(e) 在空栈上执行后得到 [e 的值]。定义 c1◃c2 为把 c1 内每个
END 替换成 c2;该运算满足结合律,且
compile(e1−e2)=compile(e1)◃compile(e2)◃(SUB;END).
(a) 写出 compile(n);(b) 写出条件表达式的编译规则,并完整编译 (ifz 1 then 2 else 3)−4;(c) 是否存在表达式族,使编译结果的语法树大小相对于原式语法树大小呈指数增长?说明理由。
Kai
(1)
[]→[2]→[3,2]→[5,3,2]→[−2,2]→[4].
(2)
[]→[3]→[]→[5]→[6,5]→[−1].
因条件 3=0,执行第二个分支。
(3)(a)–(b)
compile(n)=PUSH n;END.
compile(ifz e1 then e2 else e3)=compile(e1)◃BRANCHZ (compile(e2)) (compile(e3)).
先编译条件,再将减去 4 的后续指令接到两分支末端,得
PUSH 1;
BRANCHZ
(PUSH 2; PUSH 4; SUB; END)
(PUSH 3; PUSH 4; SUB; END)
(3)(c)
存在。令 b=(ifz 0 then 0 else 0),e0=0,ek+1=b−ek。原式语法树大小为 Θ(k)。
compile(b) 有两个 END。将 compile(ek)◃(SUB;END) 接入时,必须在两分支各复制一次。因此编译树大小满足 Ck+1≥2Ck,且 Ck+1=2Ck+O(1),故为 Θ(2k)。