言語理論とコンパイラ

第三回: 有限オートマトンと線形文法

2005年 5月 6日

AGU

© 2005 Martin J. Dürst 青山学院大学

宿題 (5月12日 11:00 まで提出)

提出は A4 の紙一枚 (裏も使ってよい)

  1. 次のプログラムの一行の字句解析の結果 (トークンの列)、構文解析の結果 (構文木)、出力 (マシーンへの命令) を書きなさい
    total = number * unitprice * (100 + tax) / 100;
  2. (提出なしだが、出来なかった人は次回ノートパソコンを持ってきてください。)
    自分のノートパソコンに cygwin をダウンロードインストールしてください。インストールの手順で必ず flexbison を選んでください。(家にダイアルアップ回線しかなかったら学校でやった方がよい。)

先週の終わり

文法 Type 言語 オートマトン
句構造文法 0 句構造言語 チューリング機械
文脈依存文法 1 文脈依存言語 線形拘束オートマトン
文脈自由文法 2 文脈自由言語 プッシュダウンオートマトン
正規文法 3 正規言語 有限オートマトン

正規言語は字句解析の時に使う。

今週の展望

これらは全て同じ力を持って、正規言語を定義・受理する

有限オートマトン

(automaton はギリシア語で、複数は automata)

有限オートマトンの状態遷移図

有限オートマトンの状態遷移図

有限オートマトンの遷移表

(≈動作関数=状態遷移関数)

a b
→A B A
B C A
*C C A

有限オートマトンに必要な物

有限オートマトンは (Q, Σ, δ, q0, F) の五字組で定義できる。

決定性と非決定性有限オートマトン

決定性 非決定性
同時に 一つの状態 複数の状態
受理条件 状態が受理状態 状態の一つ以上が受理状態
ε 遷移 不可 可能
動作関数の型 δ: Q × ΣQ δ: Q × (Σ ∪ {ε}) → 2Q

(決定性) 有限オートマトンの例

NFA から同等の DFA への変換

アルゴリズムの原理:

全ての DFA は NFA でもある。全ての NFA は同等の DFA に変換できる。

よって、DFA と NFA の受理能力が等しい。

実装は DFA の方が簡単が、テーブルは大きくなる可能性がある。

NFA から同等の DFA への変換の一例

動作関数
ε 0 1
S {A} {} {}
A {} {A,C} {B}
B {} {} {A}
C {} {} {}

DFA の最小化

ある DFA から同等の最小の DFA を次の通りに作れる:

  1. 状態を受理状態と非受理状態の二つの集合に分ける
  2. それそれの状態からどの記号でどの集合に遷移するかを調べる
  3. 現在の集合を、どの記号でも同じ集合に遷移する状態の部分集合に分ける
  4. 3. で変更がない時まで 2. から繰り返す

最小化によって効率よい実装ができるし、二つの有限オートマトンが同等であるかどうかも簡単に調べられる。

DFA の最小化の一例

文法の定義

文法は (Q, Σ, δ, q0, F) の四字組で定義できる。

書換規則は一般には悲終端記号と終端記号の列から悲終端記号と終端記号の列への規則になっている。

線形文法

文法の簡単な書換規則
規則の形 名称
A → aB 線形規則
A → Ba 線形規則
A → a 定数規則

左線形文法: 左線形規則と定数規則しか含まない文法

右線形文法: 右線形規則と定数規則しか含まない文法

左・右線形文法はともに線形文法と言い、正規文法とも言う

(左) 線形文法と有限オートマトン

左線形文法と NFA の対応 (ε が考慮外):

右線形文法も同様 (語を右から読み込むと考えられる)

左線形文法と有限オートマトンの一例

有限オートマトンの状態遷移図

A → aB | bA

B → bA | a | aC

C → bA | a | aC

正規表現の例

計算機実習 I の演習問題: ある文章中に &amp;, &quot;, &apos;, &lt;, &gt; を見つけて、それぞれ &, ", ', <, > に変換せよ。

Perl で書くと次のようになる:

s/&quot;/"/g;
s/&apos;/'/g;
s/&lt;/</g;
s/&gt;/>/g;
s/&amp;/&/g;

正規表現の形式定義

アルファベットΣ 上の正規表現と表す言語
正規表現 条件 言語 備考
ε, a a ∈ Σ {ε} 又は {a}
r|s r, s が正規表現 L(r|s) = L(r) ∪ L(s) 集合和
rs r, s が正規表現 L(rs) = L(r)L(s) 連結
r* r が正規表現 L(r*) = (L(r))* 閉含
(r) r が正規表現 L((r)) = L(r)

L(r) は r によって表されている言語。優先度は下の方が強い。

正規表現を定義する言語は文法で書けるが、正規表現は文法と違って規則は一つしか使わない。

実用化された正規表現

正規表現の便利な追加機能

正規表現の使い方による変更

正規表現から NFA へ (1)

正規表現に対応する NFA は正規表現の部分表現から再帰的に作られる。

ε と a に対応する NFA は初期状態一つと受理状態一つとそれを結ぶ ε 又は a と書かれた矢印。

r|s の NFA は r の NFA と s の NFA から次のようにつくる:

全体の初期状態から r と s の初期状態へと、r と s の受理状態から全体の受理状態へ ε で結ぶ

正規表現から NFA へ (2)

rs の NFA は r の受理状態と s の初期状態を ε で結んで、r の初期状態は rs の初期状態、s の受理状態は rsの受理状態。

r* の NFA は次のようにつくる:

全体の初期状態と r の初期状態、r の受理状態と全体の受理状態、全体の初期状態と全体の受理状態、そして r の受理状態と初期状態 (逆!) を ε で結ぶ。

NFA や DFA から正規表現を作るのも可能だが、複雑。

今週のまとめ