コンパイラ理論 3 構文解析

Download Report

Transcript コンパイラ理論 3 構文解析

コンパイラ理論 10
Racc その5 (if-then-else-end)
櫻井彰人
練習問題4: if then else end
Ruby の if then else end と if then end
相当の文が使えるようにしてください。
何となくできるようにするのは、簡単です。

しかし、おかしい!!
失敗例
例えば exp に次のようなものを付け加え
ればよい
| IF exp THEN
{ if val[1]
| IF exp THEN
{ if val[1]
exp
!=0
exp
!=0
END
then result=val[3] else result=nil end}
ELSE exp END
then result=val[3] else result=val[5] end}
a=0
if a then b=1 else b=2 end
print( "b= ", b,"\n")
b= 2
a=1
if a then b=1 else b=2 end
print( "b= ", b,"\n")
b= 2
失敗例の実行例
a=0
puts(a)
if a then puts("true") else puts("false") end
a=1
puts(a)
if a then puts("true") else puts("false") end
0
true
false
1
true
false
回避方法はあるか?
ある。action は途中に書ける。
そして、bottom up に値を渡す。

これは、継承属性を真似ることになる。
再掲: 属性文法
•
属性文法(ぞくせいぶんぽう、Attribute Grammar)とは、形式文法の生成に関す
る属性を定義する形式的手法。属性には値を関連付けられる。その言語を構文
解析やコンパイラで処理する際に、属性の評価(属性から値を得ること)が抽象
構文木上のノードで行われる。
•
属性は2種類に分類される。合成(sythesized)属性と継承(inherited)属性である。
合成属性とは、属性評価の結果として生成されるものであり、継承属性の値を使
用することもある。継承属性とは、親ノードから継承される属性である。
•
いくつかの手法では、合成属性は意味情報を構文解析木の上に渡すのに使わ
れ、継承属性は逆に下に渡すのに使われる。例えば、言語変換ツールを作成す
る場合、属性文法は構文要素に意味(値)を設定するのに使われる。また、文法
(構文規則だけでは明示的に示されない言語の規則)に従って意味論的検証を
行うことも可能である。
Wikipediaより
回避方法はあるか?
ある。action は途中に書ける。
そして、bottom up に値を渡す。

こんな具合に動く
再掲: LR構文解析動作原理 (1)
int + (int) + (int)
E  E + {むにゃ} ( E ) | int
int
+ ( int ) + ( int
)
再掲: LR構文解析動作原理 (2)
int + (int) + (int)
E + (int) + (int)
E  E + {むにゃ} ( E ) | int
E
int
+ ( int ) + ( int
)
再掲: LR構文解析動作原理 (3)
int + (int) + (int)
E + (int) + (int)
E + (E) + (int)
E  E + {むにゃ} ( E ) | int
E
int
E
+ ( int ) + ( int
)
再掲: LR構文解析動作原理 (4)
int + (int) + (int)
E + (int) + (int)
E + (E) + (int)
E + (int)
E  E + {むにゃ} ( E ) | int
E
E
int
E
+ ( int ) + ( int
)
再掲: LR構文解析動作原理 (5)
int + (int) + (int)
E + (int) + (int)
E + (E) + (int)
E + (int)
E + (E)
E  E + {むにゃ} ( E ) | int
E
E
int
E
E
+ ( int ) + ( int
)
再掲: LR構文解析動作原理 (6)
int + (int) + (int)
E + (int) + (int)
E + (E) + (int)
E + (int)
E + (E)
E
最右導出 rightmost
derivation を逆順に
E  E + {むにゃ} ( E ) | intE
E
E
int
E
E
+ ( int ) + ( int
)
回避方法のアイデア
条件部分(ifとthenの間の式)の値(仮にifvに代
入としよう)がわかったら、

それがtrueであれば、then部は、解析だけして、計算
をしないようにする。
 exp とそっくりの exp1 をつくり、その中でのアクションは、す
べて、if ifv==true then … end にする。

それがfalseであれば、else部は、解析だけして、計算
をしないようにする。
 exp とそっくりの exp2 をつくり、その中でのアクションは、す
べて、if ifv==false then … end にする。
つまり
IF exp THEN exp ELSE exp END
{ if val[1] !=0 then result=val[3] else result=val[5] end}
IF exp {値を保存} THEN exp1 ELSE exp2 END
{ if val[1] !=0 then result=val[3] else result=val[5] end}
そして
exp1:
exp1 '+' exp1 { if 条件がtrue then result += val[2] end}
など
exp2:
exp2 '+' exp2 { if 条件がfalse then result += val[2] end}
など
回避方法を試してみた
だめだった

途中でのアクションでは、valが設定されてい
ない。従って、if部の値がとれない!
racc のバグである
とりあえずの回避策
if部の式を特別にし(といっても1行だけだ
が)、結果を保存

それを参照して、then部やelse部を行う
ifをネストさせるには、stack を用いる必要
あり。まぁ、とりあえず
つまり
IF exp {値を保存} THEN exp1 ELSE exp2 END
{ if val[1] !=0 then result=val[3] else result=val[5] end}
IF expC THEN exp1 ELSE exp2 END
{ if val[1] !=0 then result=val[3] else result=val[5] end}
そして
expC: exp
{ result = val[0]; @ifresult=result }
---- inner
def initialize
@ifresult=nil
end
追加
練習問題5
では、以上の追加を行ってみてください。
前回の練習問題、ほぼこれと同じことが
出来た方は、比較をして下さい。