Document

言語処理系(1)
金子敬一
1 コンパイラ入門
1.1
コンパイラと翻訳系
1.2 翻訳系の必要性
1.3 コンパイラの構造
1.4 字句解析
1.5 構文解析
1.6 中間コード生成
1.7 最適化
1.8 コード生成
1.9 記帳
1.10 誤り処理
1.11
コンパイラ作成道具
1.12
始めるにあたって
1.1 コンパイラと翻訳系
• 翻訳系
1つのプログラミング言語(原始言語(source language)を
別のプログラミング言語(目的言語(object languageある
いはtarget language))に変換するプログラムを一般に翻
訳系(translator)とよぶ.
1.1 コンパイラと翻訳系
• コンパイラ
目的言語がアセンブリ言語や機械語であるような翻訳
系をコンパイラ(compiler)と呼ぶ.
1.1 コンパイラと翻訳系
• コンパイルと実行
コンパイルと実行は個別の2段階からなる.
原始
コード
コンパイラ
目的
コード
入力
目的コード
出力
1.1 コンパイラと翻訳系
• コンパイラの発展
• モジュール化手法の開発
コンパイルの過程を系統立てて,モジュール化
する方法が分かった
• 技法の開発
多くの作業に対して系統的な技法が見つかった
• 道具の開発
有用なソフトウェアツールの開発
1.1 コンパイラと翻訳系
• 他の翻訳系
• 中間コード
プログラミング言語を中間コードへ翻訳し,
解釈系(interpreter)で直接実行
• アセンブラ
原始言語がアセンブリ言語で,目的言語が機械語
• 前処理系
高水準言語のプログラムを同一の高水準言語の
別のプログラムへと翻訳
1.2 翻訳系の必要性
• 機械語
• 機械語プログラムは0と1の列であり,莫大な労力を
必要とする割りに,非常に誤り易いという欠点をも持
つ.
1.2 翻訳系の必要性
• 記号アセンブリ言語
• 命令コードやデータ番地に対して簡略名(mnemonic
name)を用いてプログラミングの効率を向上させよう
としている.
• 記号アセンブリ言語は,最も機械語に近い「高水準」
言語であり,機械語とほぼ1対1に対応する.
• しかしながら,計算機がアセンブリ言語を直接実行
することはできず,翻訳系であるアセンブラを必要と
する.
1.2 翻訳系の必要性
• マクロ
• アセンブリ言語などにあるテキストの置換機能のこと
MACRO ADD2 X, Y
LOAD Y
ADD X
STORE Y
ENDMACRO
ADD2 a, b
LOAD b
ADD a
STORE b
1.2 翻訳系の必要性
• 高水準言語
– マクロ機能を備えたアセンブリ言語を用いても,プロ
グラマは依然として特定の計算機に依存したコード
を生成することしかできない.
– 複雑な命令やデータ構造の内部表現を常に意識し
てプログラミングするには,莫大な労力を必要とする.
– 高水準言語では,AとBを足すにはA+Bでよい.
– コンパイラが必要.若干の性能低下.
1.3 コンパイラの構造
• フェーズ
表管理
字
句
解
析
構
文
解
析
中
間
コ
ー
ド
生
成
誤り処理
コ
ー
ド
の
最
適
化
コ
ー
ド
生
成
1.3 コンパイラの構造
•
字句解析系
–
最初のフェーズを字句解析系(lexical analyzer)と
呼ぶ.
–
原始言語の文字を字句(token)と呼ぶ論理的な塊
ごとに分離する.
–
字句にはDOとかIFとかの手掛かり語(keyword),X
やNUMとかいった識別子(identifier),+や<=といっ
た演算子記号(operator symbol)がある.
1.3 コンパイラの構造
•
構文解析系
–
構文解析系(syntax analyzer)は,字句解析系から
字句を受けとり,構文単位のまとまりを構成してい
く.
–
例えばA+Bを表現している3つの字句は,式
(expression)と呼ぶ1つの構文構造へまとめられる.
–
式はさらに他の構文構造とまとめられて文を形成
–
構文構造を葉が字句からなる木構造で表現するこ
とが多く,この木構造を解析木(parse tree)と呼ぶ.
1.3 コンパイラの構造
•
中間コード生成系
–
構文解析系の生成した構文構造を用いて,中間
コード生成系(intermediate code generator)は,中間
コードと呼ぶ一連の簡単な命令列を生成する.
–
中間コードは,マクロのようなものであり,計算機
の詳細とは独立な構造となっている.
1.3 コンパイラの構造
•
コード最適化
–
最終的な目的プログラムにおいて実行速度の向
上や使用する記憶域の抑制などを目指して中間
コードを改良するためのフェーズをコード最適化
(code optimization)という.
–
必ずあるとは限らない.
1.3 コンパイラの構造
•
コード生成
–
最後のフェーズであるコード生成(code generation)
では,以下の項目などを決定し目的コードを生成:
•
データ用の記憶位置;
•
各々のデータをアクセスするためのコード;
•
計算遂行のためのレジスタ.
1.3 コンパイラの構造
•
表管理
–
表管理(table management)では,プログラム中で使
用される名前を登録し,型などの情報を記憶して
おく.
–
情報保持のデータ構造を記号表(symbol table).
1.3 コンパイラの構造
•
誤り処理
–
ソース中に誤りを検出したときに呼び出すフェーズ.
–
できるだけ先のフェーズに進めるように,誤り処理
系(error handler)が調整する.
1.3 コンパイラの構造
•
パス
–
いくつかのフェーズをまとめてパス(pass)という.
–
パス間のデータのやり取りは中間ファイルで行う.
–
パス内のフェーズはコルーチンになりうる.
–
原則は存在しない.
1.4 字句解析
•
字句解析系
–
ソースプログラムとコンパイラとのインタフェース
–
原始プログラムを1文字ずつ読み込み,字句
(token)ごとにまとめる.
1.4 字句解析
•
字句
–
単一の論理的対象として扱うことのできる文字列
–
識別子,手掛り語,定数,演算子,区切り記号など.
–
コンパイラ設計者による任意性を持つ.しかし,
MAXをMとAXに分けるのは不自然
1.4 字句解析
•
字句の分類
–
字句は,型と値からなる対として扱う.
–
値を持たない型もある.
•
•
値を持たないもの: IFや;など
値を持つもの: 識別子,定数,名札など
1.4 字句解析
•
字句の取出し
–
原始プログラムを走査し,取り出す.先読みが必
要
IF(5.EQ.MAX)GOTO100
5か,5.0か,ある
いは5.E-10か?
1.4 字句解析
•
字句の取出し
–
原始プログラムを走査し,取り出す.先読みが必
要
IF(5.EQ.MAX)GOTO100
[if,-] [(,-] [const,341] [eq,-]
[id,729] [),-] [goto,-] [label,554]
1.5 構文解析
•
構文解析系
–
字句が原始言語として許されるか検査
–
字句を以降のフェーズで使用する木構造データに
変換
1.5 構文解析
•
検査
–
プログラミング言語PL/IにおけるA + / Bのよう
な式は,[id,…], [+,-], [/,-], [id,…]のような字句の
並びとなる.
–
演算子が2つ続くことはないので,誤りであること
がわかる.
1.5 構文解析
•
解析木
–
式A / B * Cの解釈
• CやFortran: (A / B) * C
• APL:
A / (B * C)
式
式
式
A
式
式
式
式
式
/
B
式
*
C
A
/
B
式
*
C
ちょっと休憩
(雑談)
タヒチ(フレンチポリネシア)
• ディペンダブルコンピューティングに関する環太
平洋国際会議(PRDC10)
2日(火)出発,同日タヒチ着
3日(水)~5日(金)会議
4日(土)ホテルチェックアウト;することなし
5日(日)0:05位に出る飛行機で出発,6日帰国
タヒチ(フレンチポリネシア)
タヒチ(フレンチポリネシア)
タヒチ(フレンチポリネシア)
• 感想
—食事
フランス料理,ワインなどおいしい
—物価
ほとんどのものが輸入であり,観光地であるため,ものの
値段が非常に高い
—文化
人は親切で,治安も良い
休憩おわり
1.6 中間コード生成
•
中間コード生成系
–
解析木を中間言語の表現へと変換する
1.6 中間コード生成
•
3番地コード
–
代表的な3番地コード(three-address code)の文は,
A := B op C
被演算子
演算子
1.6 中間コード生成
•
3番地コード
while A>B & A<=2*B-5 do A:=A+B;
L1:
if A>B goto L2
goto L3
L2:
T1 := 2 * B
T2 := T1 – 5
if A
goto
L4:
A :=
goto
L3:
<= T2 goto L4
L3
A + B
L1
1.7 最適化
•
最適化フェーズ
中間コードを変換して,より速く,より小さなプ
ログラムを目指す.
1.7 最適化
•
局所最適化(local optimization)
•
局所的なプログラム変換による最適化
L1:
if A > B goto L2
goto L3
L2:
T1 := 2 * B
T2 := T1 – 5
L1:
if A <= B goto L3
L2:
T1 := 2 * B
T2 := T1 - 5
1.7 最適化
•
共通部分式の削除
A := B + C + D
E := B + C + F
•
T1 := B + C
A := T1 + D
E := T1 + F
ループ最適化
•
ループ内で不変な計算(loop invariant
computation)をループの直前に移動
1.8 コード生成
•
コード生成系
•
コード生成系は,中間コードを機械コードへと変換
する.
•
機械的で単純な変換は,冗長なデータ転送を多く
含む非能率的な目的コードを生成する.
1.8 コード生成
•
レジスタ割当て
•
コード生成系では,レジスタの内容を記憶しておき,
不要なデータ転送命令を削除する.
•
これらのレジスタを効率良く使うために,レジスタ
割当て(register allocation)を行う.
•
一般に最善な割当てを求めることはNP困難な問
題⇒発見的な手法を用いる.
1.9 記帳
•
記号表
•
原始プログラム中の全データ対象に関する情報を
記入
•
変数が,整数なのか実数なのか,配列の大きさは
いくつか,関数の引数の数はいくつかなど.
1.9 記帳
•
情報の収集
•
情報はいくつかのフェーズにまたがる.
•
字句解析系で,識別子MAXを発見すると,記号表
に未記入であれば登録
•
さらに,integer MAXなる宣言を発見すると,記
号表にMAXが整数型であることを記入
1.9 記帳
•
情報の利用
•
収集した情報は多くのフェーズで利用される.
•
型誤りの検出や,暗黙の型変換.
•
意味解析(semantic analysis)
1.10 誤り処理
•
誤りの発生
•
•
•
•
•
•
字句解析系: 原始プログラムの字句の綴り誤り
構文解析系: 入力構造を確定できない構文上の
誤り
中間コード生成系: 中間コードを生成できないよ
うな不適切な型の被演算子
コード最適化系: 制御の解析の結果,到達不能
な文の検出
コード生成系: 目的機械の1語に合わない定数
記帳: 多重宣言された識別子
1.10 誤り処理
•
誤りメッセージ
•
各フェーズは,誤りを見つけたときに誤り処理系に
報告する.
•
誤り処理系は,適切なメッセージを生成する.
•
処理の継続を試みる
1.11 コンパイラ作成道具
•
作成道具
•
走査系生成系
•
構文解析系生成系
•
コンパイラコンパイラ
1.11 コンパイラ作成道具
•
入力仕様
•
原始言語の字句および構文構造の記述
•
原始言語の各構文要素に対して生成すべき出力
の記述
•
目的機械の記述
1.11 コンパイラ作成道具
•
コンパイラコンパイラの機能
•
走査系生成系
•
構文解析系生成系
•
コード生成機能
1.12 始めるにあたって
•
設計上の留意点
•
•
•
•
•
•
•
原始言語の利用目的…力点はどこか?
コンパイル時間と出力コードの質とのバランス…コ
ンパイル速度の重要性は?
誤り診断と誤り回復の能力…目的は?
目的機械の性質と操作環境…コード生成も重要
実現言語
コンパイラの生成期間
コンパイラの作成環境
変更や修正のしやすさ…改良
1.12 始めるにあたって
•
ブートストラッピング(最初のコンパイラは?)
X
Y
Z
言語Xから言語Yへの翻訳機能を持ち,
言語Zで記述されたコンパイラ
新しい言語Lを,機械語Aを持つ機械MAで使いたい.
1.12 始めるにあたって
L
A
S
L
S
A
A
A
A
ただし,S⊂L
さらに言語Lを,機械語Bを持つ機械MBでも使いたい.
1.12 始めるにあたって
L
B
L
L
L
B
A
A
A
クロスコンパイラ
L
B
L
L
L
B
A
B
B