言語理論とコンパイラ
第十回: yacc
系ツールの原理、エラー処理
2011 年 6 月 17 日
http://www.sw.it.aoyama.ac.jp/2011/Compiler/lecture10.html
Martin J. Dürst
© 2005-11 Martin
J. Dürst 青山学院大学
これからの予定
- 6月17日: yacc 系ツールの原理、エラー処理
- 6月24日: 中間表現、意味解析、コード生成
- 7月1日: コード生成、最適化
- 7月8日: 平常試験
(45分程度)、仮想計算機、ゴミ集め等
今日の予定
- 宿題について
- 優先度の扱い
- 属性文法
- 文法の種類
- エラー処理
宿題
提出: 再来週の木曜日 (6 月 23日) 19 時 00 分、O 棟 529
号室の前
簡単な電卓を有理数の電卓に拡張してください。
有理数の表現方法として、[分子,分母] を追加
してください。
[]
内には割り算は許されないように文法を設計してください。
.lex
と .y
のファイルを印刷して提出。A4
両面印刷、表紙なし、左上ホチキス止め、名前と学生番号をコメントに記述。
優先度と結合規則は文法で定義 (%left
,
%right
など使わないこと)
来週質問が可能なので、よく準備して質問できるようにすること!
宿題のヒント
- YYSTYPE は有理数が表現できる構造体;
両方の入力ファイルに同様に定義
- shift/reduce conflict や reduce/reduce conflict がありうる
.output
ファイルを見て検討
- 実際の入力で試してみる
- 文法を少しづつ拡張しながら念入りにテスト
- テストファイルを作成、文法を拡張するたびにテストを追加
- 関心の項目 (優先順位、結合規則)
を仕分けるテストを作成
- テストの結果を取っておいて、次のテストの結果と比較
- [] 内の制限の扱い: [] 内と []
外を別の非終端記号で扱う
- 入力の一例: test_in.txt
優先度の扱い
属性文法
(attribute(d) grammar(s))
- 単純な構文解析は「受理」の有無のみ
- 終端記号、被終端記号に「属性」を付ける
- 文法規則ごとに、その属性の割り出しを追加情報で定義
- 属性を解析木の下から上へと計算するのが普通が、
両方向に計算する仕組みも存在
- 例:
E0 → E1 '-' E3
S(E0
) = S(E1
) -
S(E3
)
bison の場合: $$ = $1 - $3
- 典型的な属性:
木の高さ、入力の長さ、式の評価値、部分解析木・構文木、生成されたコード
導出の順番: 最左導出と最右導出
簡単な例:
E → E '+' T
T → integer
最左導出の場合に、いつもできるだけ左の終端記号を置き換える
文法の種類の呼び方
- LL: 左から入力を読んで、最左導出
- LR: 左から入力を読んで、最右導出 (逆順)
- LL(1): LL で、先読みはトークン一つに限定
- LR(1): LR で、先読みはトークン一つに限定
- LALR: LR (1) の一種で、yacc、bison など幅広く使用
LALR 構文解析の原理
スタックを使って読んだトーケンや途中の非終端記号を蓄積
オートマトンを使ってできるだけ簡単な操作で次のステップを決定
(LA)LR 構文解析の三つのオペレーション
- shift:
トークンを一個読んで、そのトークンをスタックにステートと一緒に詰める
- reduce:
スタックの上部にあるトークンや非終端記号を文法規則を使って一つの終端記号に変換
reduce 後には go to を使って状態を移動することがある
- accept: 入力を受理、作業を終了
構文エラー処理
- エラー処理の難しさ
- エラー処理の要点
- エラー処理の技法
エラー処理の難しさ
- 一つの正しいプログラムに対してエラーのプログラムは多数ある
- 人間にとって間違いやすいものと間違いにくいものをプログラムで区別するのが困難
- 構文解析には理論があるが、エラー処理には理論が少ない
エラー処理の要点
- 分かりやすいエラーメッセージを出す
- 一つだけではなく、複数のエラーを見つける
- 二次エラーをできるだけ出さない
- 正しいプログラムの処理を遅くさせない
- コンパイラを複雑化しない
エラー処理の技法
- 文法に合ったトークンを見つけるまでにトークンを捨てる
(panic mode)
- 少数のトークンを追加又は入れ替え
- 文法にエラーをキャッチする規則を追加 (error
productions)
- 入力に一番近い正しいプログラムを探す
bison でのエラー処理