プログラム言語の構文を定義する形式についての概観
元となる言語
contact mfowler { email: fowler@acm.org }
BNF1
contact : 'contact' Identifier '{' email '}' ; email : 'email:' Identifier '@' Identifier ;
BNF2:Algol BNF
<contact> ::= contact <Identifier> { <email> } <email> ::= 'email:' <Identifier> @ <Identifier>
BNF3;電話番号が入る場合
contact : 'contact' username '{' line '}' ; username : Identifier; line : email | tel ; email : 'email:' EmailAddress ; tel : 'tel:' TelephoneNumber ;
多重度シンボル
BNF4:電話番号は複数あるかもしれない
contact : 'contact' username '{' fullname? email+ tel* '}'; username : Identifier; fullname : QuotedString; email : 'email:' EmailAddress ; tel : 'tel:' TelephoneNumber ;
BNF4':サブルールのインライン化
contact : 'contact' Identifier '{' QuotedString? ('email:' EmailAddress)+ ('tel:' TelephoneNumber)* '}' ;
- サブルールの方が意図が明確になる
BNF5:多重度シンボルの代わりにカッコを使う
contact : 'contact' username '{' [fullname] email {email} {tel} '}'; username : Identifier; fullname : QuotedString; email : 'email:' EmailAddress ; tel : 'tel:' TelephoneNumber ;
- ? → [ . . ] / * → { . . }
EBNFを基本BNFに変換する
BNF6:?のかわりに|を使う
contact : 'contact' username '{' fullname email+ tel* '}'; username : Identifier; fullname : /* optional */ | QuotedString ; email : 'email:' EmailAddress ; tel : 'tel:' TelephoneNumber ;
- a : b? c → a: c | b c.
BNF7:*のかわりに|を使う
contact : 'contact' username '{' fullname email+ tel '}'; username : Identifier; fullname : /* optional */ | QuotedString ; email : 'email:' EmailAddress ; tel : /* multiple */ | 'tel:' TelephoneNumber tel;
- x : y*; → x : y x |;
BNF8:+のかわりに|を使う
contact : 'contact' username '{' fullname email tel '}'; username : Identifier; fullname : /* optional */ | QuotedString ; email : singleEmail | email singleEmail; singleEmail : 'email:' EmailAddress ; tel : /* multiple */ | 'tel:' TelephoneNumber tel;
- x : y+ → x : y | x y.
コードアクション
BNF9:ログ出力
contact : 'contact' username '{' email? tel? '}'; username: ID; email : 'email:' EmailAddress {log("got email");}; tel : 'tel:' TelephoneNumber;
BNF10:要素の参照 - Antlrの場合
contact : 'contact' username '{' email? tel? '}'; username: ID; email : 'email:' e=EmailAddress {log("got email " + $e.text);}; tel : 'tel:' TelephoneNumber;
- yaccの場合は、インデックスを使う
BNF11:ルールの参照
contact : 'contact' username '{' e=email? tel? '}' {log("email " + $e.text);} ; username : ID; email : 'email:' EmailAddress ; tel : 'tel:' TelephoneNumber;
BNF12:戻り値と変数の定義
contact : 'contact' username '{' e=email? tel? '}' {log("email " + $e.result);} ; username : ID; email returns [EmailAddress result] : 'email:' e=EmailAddress {$result = new EmailAddress($e.text);} ; tel : 'tel:' TelephoneNumber;
表現解析文法
contact : email / tel;
- まずemailをトライしてからtelを見る