言語理論とコンパイラ

第七回: 下向き構文解析

2010 年 5月 21日

http://www.sw.it.aoyama.ac.jp/2010/Compiler/lecture7.html

Martin J. Dürst

AGU

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

目次

前々回からの宿題: Flex

[都合により削除]

前回の宿題

C プログラム言語など知っている言語やデータ形式の文法を調べなさい (提出不要):

C プログラム言語の文法の例 (yacc 形式; typedef に要注意)

Java プログラム言語の文法 (BNF 形式)

Ruby プログラム言語の文法 (図)

前回からの残り

前回のまとめ

構文解析の目的

構文解析の難しさ

構文解析の結果: 解析木と構文木

解析木 (parse tree, concrete syntax tree):
構文木 (抽象構文木、abstract syntax tree):

解析木と構文木の例

文法:

E → E '+' E    (Expression, 式)

E → E '*' E

E → '(' E ')'

E → integer

入力の例:

5 + 3 * (7 + 2)

解析の実装: 下向き解析と上向き解析

下向き構文解析 (top-down parsing):
解析木を上から (初期記号から) 作る
上向き構文解析 (bottom-up parsing):
解析木を下から (終端記号から) 作る
途中に複数の (小さな) 解析木がある

下向き解析の一般概要

バックトラックの要点

バックトラックの遅さへの対策:

次のトークンしか見なくてよい文法に限定したい

再帰的下向き構文解析

下向き構文解析の実装: 簡単な手作りコンパイラ

プログラム: scanner.h, scanner.c, parser1.c, parser.c

曖昧な文法

文法の曖昧性の除去

問題の例:

E → E '-' E | integer

入力 4 - 5 - 7 に対して複数の解析木が作れる

解析木によって計算結果が違う

解決方法: 文法の書き換え

E → E '-' integer | integer

左再帰の問題と解決

左再帰の例:

E → E '-' integer | integer

間違った解消 (結合規則が違う):

E → integer '-' E | integer

解消の結果:

E → integer EE

EE → '-' integer EE | ε

これに相当する EBNF:

E → integer ('-' integer)*

文法規則と BNF

文法規則には色々な書き方がある:

  1. 一番単純な書き方: 矢印だけ
  2. 左側に同じ被終端記号を持つものを複数組み合わせて | で選択を表す
    ⇒ 根本的に 1. と変わらない (syntactic sugar/糖衣構文)
  3. 正規表現の ? の様なもの (あり/無し) の追加 (よく [...] で書く)
    ⇒ 二つの構文規則に分けることが可能
  4. 正規表現の * の様なもの (よく {...} で書く)
    ⇒ 書き換えが可能

上記の拡張を含む文法規則の書き方は BNF (Backus-Naur Form), EBNF (Extended...), ABNF (Augmented...) などという

EBNF の書き換え

M → a N* b

M → a b | a L b
L → L N

(文脈自由) 文法の書き方の拡張

こういう風な記述は EBNF (Extended Backus Naur Form) という

様々な種類 (方言) が存在

文法と正規表現の違い

文法:

正規表現:

正規表現の (簡単な) 規則は文法の (複雑な) 規則一つに相当する

下向き構文解析の問題点

文法の追加条件

⇒ 文法は言語を定義するだけでは不十分

宿題

(提出不要)

次の文法の曖昧性を除去し、曖昧性のない文法を作りなさい。曖昧性がないことを複数の例で確認してください。

E → E '+' E    (Expression, 式)

E → E '*' E

E → '(' E ')'

E → integer

ヒント: 非終端記号の追加が必要