言語理論とコン
パイラ
第十回:
意味解析と中間表現
http://www.sw.it.aoyama.ac.jp/2005/Language%20Theory%20and%20Compilers/lecture9.html
© 2005 Martin
J. Dürst 青山学院大学
今日の予定
- 先週からの宿題
- エラー処理
- 中間表現 (構文木、名前表)
- 意味解析
先週からの宿題
簡単なプログラム言語を bison で実現して、bison の
.y
ファイルを印刷して提出:
- データ型は整数のみ
- 変数の識別子は一文字 (A-Za-z), 初期値は 0
- 多くの C の演算子を実現する
- 演算子の優先度、結合規則を文法で定義する (%left,
%right など使わないこと)
- 文は
;
で区切る。制御文 (if
等)、関数 は無し
@ (式)
は「式」の結果を改行付きに印刷する。
宿題関連のプリント
宿題の要点
- 優先度: 式の種類 (項、因子など)
ごとに非終端記号
- 結合規則: 左結合に左再帰、右結合に右再帰
- 変数:
グローバル変数の配列を用意して、文字の番号を指数に
- 演算子ごとに必要な処理: C に任せる
言語理論のまとめ
文法 |
Type |
言語 |
オートマトン |
句構造文法 |
0 |
句構造言語 |
チューリング機械 |
文脈依存文法 |
1 |
文脈依存言語 |
線形拘束オートマトン |
文脈自由文法 |
2 |
文脈自由言語 |
プッシュダウンオートマトン |
正規文法 |
3 |
正規言語 |
有限オートマトン |
構文エラー処理
- エラー処理の難しさ
- エラー処理の要点
- エラーの技法
エラー処理の難しさ
- 一つの正しいプログラムに対してエラーのプログラムは多数ある
- 人間にとって間違いやすいものと間違いにくいものはプログラムに区別できない
- 構文解析には理論があるが、エラー処理には理論がない
エラー処理の要点
- 分かりやすいエラーメッセージを出す
- 一つだけではなく、複数のエラーを見つける
- 二次エラーをできるだけ出さない
- 正しいプログラムの処理を遅くさせない
- コンパイラを複雑しすぎない
エラー処理の技法
- 文法に合ったトーケンを見つけるまでにトーケンを捨てる
(panic mode)
- 少数のトーケンを追加又は入れ替える
- 文法にエラーをキャッチする規則を追加する
- 入力に一番近い正しいプログラムを探す
bison でのエラー処理
error
トーケンを文法に追加できる
- エラーが起こると bison が一番近い
error
トーケンの含まれる規則までエラー前のトーケンや非終端記号を捨てる
- その規則の
error
トーケンの後に来るトーケンが来る入力も捨てる
コンパイラの段階
字句解析 (lexical analysis)
構文解析 (parsing; syntax analysis)
意味解析 (semantic analysis)
最適化 (optimization)
コード生成 (code generation)
中間表現: 名前表
- 提供する機能:
- 名前の検索
- 名前の登録と取り消し
- 名前についてのデータの管理
- 要点:
- 使うことが多くて、名前の数が多いので効率が大切
- 同じ名前が複数ある可能性があるので区別が必要
名前表が扱うデータ
- 名前の種類 (変数、関数、型など)
- 定義か宣言だけか
- 変数、関数などの型
- 名前が有効な領域 (例えば関数、ブロック)
- 変数などの場合: 大きさ
- 関数、変数などのアドレス
中間表現: 構文木
簡単なプログラム言語と簡単なマシーン・アーキテクチャの場合
(例えば Pascal からスタック・マシーン)
には構文解析しながらコード生成を行うこともある
構文木の生成:
構文規則ごとの処理で再生する。例えば:
expression: expression '+' term { $$ = $1 + $3; }
を次に変える:
expression: expression '+' term
{ $$ = newnode(PLUS, $1, $3; }
(YYSTYPE
も変える)
構文木は普通二分木が、関数の引数などに特別な措置が必要
意味解析
- 主に型の処理:
- 型が合うかどうかのチェック
- 必要に応じて型の自動変換
(構文木に新たなノードの追加)
- 構文木の生成の時にするか後にするか
- 型が同じかどうか複数の定義がある:
- 同じ名前の型が同じ
(簡単だが利用者にとって不便)
- 同じ中身の型が同じ (複雑)