言語理論とコンパイラ

第四回: 正規表現と字句解析

2008年 5月 2日

http://www.sw.it.aoyama.ac.jp/2008/Compiler/lecture4.html

Martin J. Dürst

duerst@it.aoyama.ac.jp, O 棟 529号室

AGU

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

今日の内容

今週の展望

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

これらは字句解析に使われる

線形文法

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

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

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

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

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

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

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

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

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

A → aB | bA

B → bA | a | aC

C → bA | a | aC

正規表現の例

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

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

gsub /&quot;/, '"'
gsub /&apos;/, "'"
gsub /&lt;/,   '<'
gsub /&gt;/,   '>'
gsub /&amp;/,  '&'

正規表現の形式定義

アルファベットΣ 上の正規表現と表す言語
優先度 正規表現 条件 言語 備考
ε, 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 の受理状態と初期状態 (逆!) を ε で結ぶ。

有限オートマトンから正規表現へ

変換は可能が、複雑

変換の原理:

  1. 状態 A から状態 B へ直接遷移できる正規表現を全ての状態の組み合わせのために作る。
  2. 一個の状態だけを選んで、その状態の経由を含める正規表現を作る。
  3. 2. のステップを繰り返して、経由できる状態を増やす。
  4. 途中で正規表現がどんどん複雑になるので、できる限り簡単化する

コンパイラの段階

字句解析 (lexical analysis)

構文解析 (parsing; syntax analysis)

意味解析 (semantic analysis)

最適化 (optimization)

コード生成 (code generation)

コンパイラの構造の実装

前半 (解析) もしくは全体は構文解析が中心

構文解析は getNextToken() みたいな関数で字句解析から必要におおじてトーケンを取り寄せる

構文解析は必要におおじて意味解析などを呼ぶ

字句解析の実装

主な要点:

選択肢:

今週のまとめ

演習問題

(提出不要)

  1. 次の正規表現を NFA に変換し、NFA から DFA を作る:
    (a|c*)a|b
  2. 1. の言語を定義する線形文法を作る。
  3. Σ = {0, 1} の 0 が偶数 (1 は何個でもよい) 語を受理する DFA を作る。
  4. (発展問題) 3. の言語の正規表現を作る。(ヒント: 変換するより正規表現を新たに作る方がいい)

来週の予定と準備

予定:

準備: