第四回: 正規表現と字句解析
2009 年 5 月 8 日
http://www.sw.it.aoyama.ac.jp/2009/Compiler/lecture4.html
© 2005-9 Martin J. Dürst 青山学院大学
これらは全て同じ力を持って、正規言語を定義・受理する
これらは字句解析に使われる
計算機実習 I の演習問題: ある文章中に
&, ", ',
<, > を見つけて、それぞれを
&, ", ', <,
> に変換せよ。
Ruby で書くと次のようになる:
gsub /"/, '"' gsub /'/, "'" gsub /</, '<' gsub />/, '>' gsub /&/, '&'
| 優先度 | 正規表現§ | 条件 | 言語 | 備考 |
|---|---|---|---|---|
| ε, a | a ∈ Σ | {ε} 又は {a} | ||
| 低い | r|s | r, s が正規表現 | L(r|s) 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 によって表されている言語。優先度は下の方が強い。
ある正規表現が定義する言語は文法でも書けるが、正規表現は文法と違って規則は一つしか使わない。
正規表現 (全ての正規表現の集合) も言語であるが、正規言語ではない。
§ 正規表現の文法: R → ε, R →a, R →b,..., R →R|R, R →RR, R →R*, R →(R)
word(aa)*a)、偶数
((aa)*)、3で割れば余りが 2
(aa(aaa)*)、等abc(a|b|c)*(a|b|c)*abc(a|b|c)*abc(a|b|c)*正規表現の便利な追加機能 (括弧内は相当の理論的な正規表現)
.: 文字一個 (a|b|c|...)+: 一個以上の r
(rr*)?: r の有無 (r|ε,
その代わり ε は使わない){m,n}:
m 個以上 n 個以下の r
(r...rr?...r?)[acdfh]: 複数の文字から選択
(a|c|d|f|h)[b-f]: b から f の字 (b|c|d|e|f)\* 等: \ はエスケープに使われる正規表現の使い方による変更
^ と $
で語の先頭と最後をマッチ正規表現に対応する NFA は正規表現の部分表現から再帰的に作られる。
ε と a に対応する NFA は初期状態一つと受理状態一つとそれを結ぶ ε 又は a と書かれた矢印。
r|s の NFA は r の NFA と s の NFA から次のようにつくる:

rs の NFA は r の受理状態と s の初期状態を ε で結んで、r の初期状態は rs の初期状態、s の受理状態は rsの受理状態。
r* の NFA は次のようにつくる:

変換は可能が、複雑
変換の原理:
字句解析 (lexical analysis)
構文解析 (parsing; syntax analysis)
意味解析 (semantic analysis)
最適化 (optimization)
コード生成 (code generation)
前半 (解析) もしくは全体は構文解析が中心
構文解析は getNextToken() みたいな関数で字句解析から必要に応じてトークンを取り寄せる
構文解析は必要に応じて意味解析などを呼ぶ
主な要点:
選択肢:
(提出不要)
(a|c*)a|b予定:
準備: