Transcript Compilers

Compilers ~chapter2~
電子情報学科 4年
早津 政和
概要
コンパイラの基礎知識
 コンパイラ
 フェーズ
 フロント・バックエンド
単純なコンパイラ
 文法解釈の前に
 文法指向翻訳
 語彙解釈
 シンボルテーブル
 中間コードと
スタックマシン
 実装
The phase of a compiler
いくつかのフェーズに分けられる








語彙解析
構文解析
意味解析
中間コード生成
コード最適化
コード生成
シンボルテーブル管理
エラー処理
Front End
Back End
Front & Back Ends
Source language
Target machine
Front end
依存する
依存しない
Back end
依存しない
(中間コードに依存する)
依存する
作ってみよう
単純なコンパイラの作成を通して、様々な
テクニックを紹介する(front endのみ)
“infix→postfix translator”を作ろう

+,-で分けられた数字のみの表現を考える
ex) 9 - 5 + 2

後からもう少し一般的な表現(数、変数、その
他の演算子)も扱えるように拡張していく
ex) (153*m + 5) mod 4 + d
文法解釈の前に
そもそもInfix/postfix notationとは?
文法を記述するには?
→Context-free grammar & Parse tree
文法の曖昧さの排除
Infix/Postfix Notation
infix notation(中置記法=挿入記法)


オペランドの間に演算子を置く書き方
数学の世界で一般に用いられている
postfix notation(後置記法=逆ポーランド記法)


オペランドの後に演算子を置く書き方
解釈が一意に決まるため、括弧を必要としない
ex) (9 – 5) + 2 → 9 5 - 2 +,
9 – (5 + 2) → 9 5 2 + -
→直接機械語に変換することが可能
Postfix Notation
Eの後置記法の定義
Eの後置記法表現をE’とすると
1.Eが変数または定数のとき、E’ = E
2.EがE1 op E2と表されるとき(opは演算
子)
E’ = E1’ E2’ op
3.Eが(E1)と表されるとき、E’=E1’
Context-free grammar
4つの構成要素
1.終端記号
2.非終端記号
3.production
(右→左)
4.開始記号(非終端
記号のひとつ)
ex)「+、-で分けられた数
字」
list → list + digit
list → list -digit
list → digit
digit →
0|1|2|3|4|5|6|7|8|9
Parse Tree
parse treeの性質
1.根は開始記号
2.葉はトークンまたは
空
3.節は非終端記号
4.Aの子の節が左から
X1,…,Xnとなっている
とき、A→X1・・・Xnは
production
list
list
list
digit
digit
digit
9
-
5
+
2
Ex) parse tree for 9-5+2
Ambiguity
1) 9-5+2 の解釈は
(9-5)+2 or 9-(5+2) の2通り
⇒+, -, *, / は左と関連付けられる
(左から実行される)
cf) = (代入)は
右
2) 9+5*2の解釈は
(9+5)*2 or 9+(5*2) の2通り
⇒*, / は+, - より先行される
Syntax-Directed Translation
コンパイラの front end を設計するのに非
常に役立つテクニック
文法的構成要素+属性
「属性」・・・型、文字列、格納場所、等
意味的規則→属性の値を計算、統合
Semantic Rule
& Semantic Action
この章では、深さ優先で節を訪問し、意味
的規則に基づいて属性を評価していく
意味的動作を production の右側に埋め
込むことで、翻訳結果を表示できる
⇒ parse tree を作成する必要がなくなる
Parsing
トークンの列が文法に合っているか決める
3
2
文脈自由文法だとO(n )、O(n )を実現するには
コストがかかるが、プログラミング言語を導入す
ると、O(n) も可能に
文法解析手法


top-down : 手作業で効果的な解析機が設計できる
bottom-up : 多くの種類の文法や翻訳手法が扱える
Predictive Parsing
top-down parsing の一種
初めの記号がproductionの右側で生成されうる
か、という情報を用いる
手順
A→αのとき、FIRST(α):αの初めの記号群
1.記号を先読みし、FIRST(α)と比較
2.非終端記号に当たるごとにproductionの右側
の役目をする関数を呼び出し、文法規則に当て
はまるかをチェックする
Left Recursion
非終端記号で始まる production は、無限
ループを引き起こす可能性がある
Predictive parser はこの左再帰形文法を
扱えないため、これを排除する必要がある
ex) A → Aα| Aβ|γ (左再帰形)
⇒A → γR
R → αR |βR |ε
※ε:空
Lexical analysis
入力をトークンに変換し、parser に渡す
ひとつのトークンを構成する連続した入力
文字列を lexeme と呼ぶ
read
character
input
push back
character
Lexical
analyzer
pass token &
it’s attributes
parser
Lexical Analyzer
「空白」とコメントの除去
トークン間の「空白」(空白、タブ、改行)とコメントを無視する
定数
数(連続した数字)を、<num, 31> のように数を表す
トークンとその値を表す属性の組、とする
変数とキーワードの認識
count = count + increment ; ⇒ id = id + id ;
のように認識、属性としてsymbol table へのポインタを持つ、とする。
begin, end, if, …のキーワードを変数と区別するためには、それらを
予約語とし、変数名として使えないようにする
Symbol Table
symbol Table は lexeme の保存と検索を請け負う
関数
insert(s, t) : 新しく格納した文字列 s&トークンtの
インデックスを返す
lookup(s) : 文字列sが格納されていればその
インデックス、なければ0を返す
キーワード
予約語として扱うため、初めに insert で格納する。
Stack machines
L-values & R-values
l-values : "locations"
r-values : "values“
Stack Manipulation
push ν, pop
rvalue l , lvalue l
:= , copy
Control Flow
絶対ジャンプ、相対ジャンプ、
シンボリックジャンプがある
label l , goto l
gofalse l , gotrue l
halt
Emitting a Translation
emit
では実装
Infix expressions
init.c
lexer.c
symbol.c
parser.c
emitter.c
Postfix expressions
error.c
Putting the techniques
together(1)
The Lexical Analysis Module : lexer.c
関数 lexan() は parser から呼ばれ、トークンを返す。変
数があった場合には symtable に格納する。改行があっ
たらlineno の値を増やす。
The Parser Module : parser.c
演算子の先行順を考慮し、左再帰形を排除。関数 parse()
が文法の初めの記号から実行を始め、新しいトークンが
必要になったら関数 lexan() を呼ぶ。表示に関数 emit()
を呼ぶ。文法違反の際は関数 error を呼ぶ。
Putting the techniques
together(2)
The Emitter Module : emitter.c
関数 emit(t, tval) でトークン、または属性の値を出力する。
The Symbol-Table Module : symbol.c & init.c
関数 lookup(s, t)、insert(s) に関しては “Symbol Table”
の項で述べた通り。関数 init() はキーワードをsymbol
table に格納する。
The Error Module : error.c
エラーメッセージとその行番号を表示して死ぬ。
GO! E EXE