Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LL(1)構文解析の紹介

 LL(1)構文解析の紹介

構文解析に馴染みが無い人向けに、LL(1)構文解析の概要を紹介したプレゼンテーション資料です。

Avatar for Opt Technologies

Opt Technologies

August 23, 2019
Tweet

More Decks by Opt Technologies

Other Decks in Programming

Transcript

  1. BNFの変形 BNFの変形 E ::= A ("+" E) | A ("-"

    E); A :: = | E "*" E | E "/" | "(" E ")" | N;
  2. BNFの変形 BNFの変形 E ::= A ("+" E) | A ("-"

    E) | A; A ::= | P ("*" A) | P ("/" A) | P; P ::= | "(" E ")" | N;
  3. BNFの変形 BNFの変形 E ::= A ("+" E | "-" E

    | ""); A ::= P ("*" A | "/" A | ""); P ::= | "(" E ")" | N;
  4. お題のBNF お題のBNF input: "1+2" E ::= A ("+" E |

    "-" E | ""); A ::= P ("*" A | "/" A | ""); P ::= | "(" E ")" | N;
  5. Eの呼び出し Eの呼び出し input: "1+2" E ::= /* -> */ A

    ("+" E | "-" E | ""); A ::= P ("*" A | "/" A | ""); P ::= | "(" E ")" | N;
  6. Aの呼び出し Aの呼び出し input: "1+2" E ::= /* => */ A

    ("+" E | "-" E | ""); A ::= /* -> */ P ("*" A | "/" A | ""); P ::= | "(" E ")" | N;
  7. Pの呼び出し Pの呼び出し input: "1+2" どちらに分岐する︖ 1⽂字「先読み」する FIRST(N) = {"0", "1",

    ..., "9"} FIRST("(") = {"("} N が選択される → ⼊⼒が「消費される」 E ::= /* => */ A ("+" E | "-" E | ""); A ::= /* => */ P ("*" A | "/" A | ""); P ::= /* -> */ "(" E ")" | N;
  8. Aの呼び出し Aの呼び出し input: "+2" どれに分岐する︖ 1⽂字「先読み」する FIRST("*") = {"*"} FIRST("/")

    = {"/"} FOLLOW("") = {"+", "-"} ""が選択される → ⼊⼒が「消費されない」 E ::= /* => */ A ("+" E | "-" E | ""); A ::= P /* -> */ ("*" A | "/" A | ""); P ::= | "(" E ")" | N;
  9. Eの呼び出し Eの呼び出し input: "+2" どれに分岐する︖ 1⽂字「先読み」する FIRST("+") = {"+"} FIRST("-")

    = {"-"} FOLLOW("") = {"*", "/"} "+" Eが選択される → ⼊⼒が「消費される」 E ::= A /* => */ ("+" E | "-" E | ""); A ::= P ("*" A | "/" A | ""); P ::= | "(" E ")" | N;
  10. Eの呼び出し Eの呼び出し input: "2" E ::= A /*→*/ ("+" E

    | "-" E | ""); A ::= P ("*" A | "/" A | ""); P ::= | "(" E ")" | N;
  11. Aの呼び出し Aの呼び出し input: "2" E ::= /* => */ A

    ("+" E | "-" E | ""); A ::= P /* -> */ ("*" A | "/" A | ""); P ::= | "(" E ")" | N;
  12. Pの呼び出し Pの呼び出し input: "2" どちらに分岐する︖ 1⽂字「先読み」する FIRST(N) = {"0", "1",

    ..., "9"} FIRST("(" E ")") = {"("} N が選択される → ⼊⼒が「消費される」 E ::= /* => */ A ("+" E | "-" E | ""); A ::= /* => */ P ("*" A | "/" A | ""); P ::= /* -> */ "(" E ")" | N;
  13. LL(1)構⽂解析における字句解析の必要性 LL(1)構⽂解析における字句解析の必要性 次のような⽂法を考える S ::= "if" "(" E ")" E

    "else" E | I; I ::= [a-zA-Z_] [a-zA-Z_0-9]*; 1⽂字先読みでは決定できない︕ FIRST("if") = {"i"} FIRST([a-zA-Z_]) = {"a",..."Z","_"}; LL(1)構⽂解析では普通、以下のようにこう考える S ::=<IF> <LPAREN> E <RPAREN> E <ELSE> E | <ID> これで1「トークン」先読みで決定できる
  14. LL(k) (k >= 2) 構⽂解析 LL(k) (k >= 2) 構⽂解析

    k トークン先読みで分岐が決定できる ⼿書きだと難しい 構⽂解析器⽣成系でも難しい(計算コストの問題) ANTLRはうまく問題を解決した JavaCCは、部分的にkを1より⼤きくする機能がある
  15. PEG(Ford04) PEG(Ford04) 字句解析は要らない S <- "if" "(" E ")" E

    "else" E / [a-zA-Z_] [a-zA-Z_0-9]*; 最初に"if"を試して、失敗したら次の選択肢を試す ナイーヴにやると最悪指数関数時間 * メモ化(Packrat Parsing)で線形時間で解析可能
  16. Coco/R Coco/R LL(k) 多⾔語対応 C#, C++, F#, VB.NET, Swi ,

    Oberon(!), etc. http://www.ssw.uni-linz.ac.at/Coco/