読者です 読者をやめる 読者になる 読者になる

PHPで字句解析 + 構文木生成ツールを作る その3

俺俺BNFから文法規則を生成できるようになりました。
試しにJSONの文法を定義してみます。

// json_grammar.txt
// 俺俺BNF

space := SPACE

comment := "//" LINE

ignore := (space | comment)*

@leaf
string_val := DOUBLE_QUOTE_STRING_ITEM*
string := "\"" string_val "\""

@leaf
key_val := DOUBLE_QUOTE_STRING_ITEM*
key := "\"" key_val "\""

@leaf
true := "true"

@leaf
false := "false"

@leaf
number := ("-")? DECIMAL_INTEGER ("." DIGIT+)? ([eE] [-+]? DIGIT+)?

@leaf
null := "null"

literal := (string | true | false | null | number) ignore

value := literal | object | array


@node
array := "[" ignore (value ("," ignore value )*)? "]" ignore


@node
key_and_value := key ignore ":" ignore value 

@node
object := "{" ignore (key_and_value ("," ignore key_and_value)*)? "}" ignore


@node
json := ignore (object | array | value)*

PHPのコード

<?php
include_relative( 'BNFProcessor.php');

$json_grammar_bnf = file_get_contents( 'json_grammar.txt');

// ここで文法生成
$p = new BNFProcessor();
$grammars = $p->process( $json_grammar_bnf);

// json text
$text = '{"menu": {
  "id": "file",
  "value": "File",
  "popup": {
    "menuitem": [
      {"value": "New", "onclick": "CreateNewDoc()"},
      {"value": "Open", "onclick": "OpenDoc()"},
      {"value": "Close", "onclick": "CloseDoc()"}
    ]
  }
}}';

// さっき生成した文法でJSONテキストを解釈して構文木を表示
$node = $grammars['json']->process( $si = new StringIterator( $text));
$node->display();

これを実行すると…

json {
   object {
      key_and_value {
         key_val('menu')
         object {
            key_and_value {
               key_val('id')
               string_val('file')
            }
            key_and_value {
               key_val('value')
               string_val('File')
            }
            key_and_value {
               key_val('popup')
               object {
                  key_and_value {
                     key_val('menuitem')
                     array {
                        object {
                           key_and_value {
                              key_val('value')
                              string_val('New')
                           }
                           key_and_value {
                              key_val('onclick')
                              string_val('CreateNewDoc()')
                           }
                        }
                        object {
                           key_and_value {
                              key_val('value')
                              string_val('Open')
                           }
                           key_and_value {
                              key_val('onclick')
                              string_val('OpenDoc()')
                           }
                        }
                        object {
                           key_and_value {
                              key_val('value')
                              string_val('Close')
                           }
                           key_and_value {
                              key_val('onclick')
                              string_val('CloseDoc()')
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }
}

きちんと構文木が生成されていることがわかります。