Perl 6で文法を作成する方法

プログラミングの文法は、テキストを解析するための一連のルールです。 これは非常に便利なことです。たとえば、文法を使用して、テキストの行が特定の標準に従っているかどうかを確認できます。 Perl 6には組み込みの文法サポートがあります。 それらは簡単に作成できるため、開始すると、どこでも使用できることがわかります。



最近、Perl 6モジュールの基本構造を作成するための簡単なアプリケーションであるModule :: Minterに取り組んでいますが、提案されたモジュール名がPerl 6命名標準に準拠していることを確認する必要がありました。



モジュール名は、2つのコロンで区切られた識別子です。 識別子は、アルファベット文字(az)またはアンダースコアで始まり、その後に英数字が続く必要があります。 確かに、一部のモジュールはコロンなしで1つの識別子のみを持つことができますが、他のモジュールは多くを持つことができます( HTTP ::サーバー::非同期::プラグイン::ルーター::シンプル )。



文法を決定します



Perl 6では、文法はレギュラーに基づいています。 識別子用とコロン区切り用の2つが必要です。 識別子については、次を設定します。



<[A..Za..z_]> #      <[A..Za..z0..9]> ** 0..* #    -
      
      







Perl 6のレギュラーを使用していることを思い出してください。ここでは、すべてが少し異なって見えます。 文字クラスは<[...]>によって決定され、範囲はダッシュではなく演算子...によって決定されます。 この規則性は、最初の文字またはアンダースコアと一致し、その後にゼロ個以上の英数字が続きます。



2つのコロンを使用すると、すべてが簡単になります。



 \:\: #  
      
      







文法は、キーワードgrammarとそれに続く名前を使用して識別されます。 この文法にLegalという名前を付けます::モジュール::名前



 grammar Legal::Module::Name { ... }
      
      







これで通常のトークンを追加できます:



 grammar Legal::Module::Name { token identifier { #   -   _ <[A..Za..z_]> <[A..Za..z0..9]> ** 0..* } token separator { \:\: #   } }
      
      







各文法には、先頭を示すTOPトークンを割り当てる必要があります。



 grammar Legal::Module::Name { token TOP { # ,        separator - identifier ^ [] ** 0..* $ } token identifier { #   -   _ <[A..Za..z_]> <[A..Za..z0..9]> ** 0..* } token separator { \:\: #   } }
      
      







TOPトークンは、解決されたモジュール名が識別子トークンで始まり、その後にセパレータと識別子トークンのゼロ以上のペアが続くことを決定します。 そのようなことを維持することは非常に簡単です-区切り文字にダッシュが含まれるようにルールを変更したい場合、1つのトークンのみで規則性を更新します。



文法を使用する



parseメソッドは、その行で文法を実行し、成功すると一致オブジェクトを返します。 次のコードは、行$ posed_module_nameを処理し、一致オブジェクトまたはエラーメッセージを表示します。



 my $proposed_module_name = 'Super::New::Module'; my $match_obj = Legal::Module::Name.parse($proposed_module_name); if $match_obj { say $match_obj; } else { say '      - , ?!'; } : 「Super::New::Module」 identifier => 「Super」 separator => 「::」 identifier => 「New」 separator => 「::」 identifier => 「Module」
      
      







一致オブジェクトのコンテンツを取得する



一致オブジェクトのコンテンツ全体をダンプすることはできませんが、再生されたトークンを抽出します。 次のコードでは、名前付きの正規表現とハッシュキーを使用しています。



 say $match_obj[0].Str; # Super say $match_obj[1].Str; # New say $match_obj[2].Str; # Module say $match_obj; #  
      
      







アクションクラス



Perl 6では、再生されたトークンの追加の動作を定義するアクションクラスを追加できます。 モジュール名に含まれる識別子が多すぎる場合に警告を追加するとします。 まず、アクションクラスを設定します。



 class Module::Name::Actions { method TOP($/) { if $.elems > 5 { warn '      – , ?.. '; } } }
      
      







これはPerl 6の通常のクラス定義です。最初の文法トークンに一致するTOPメソッドを追加しました。 次に、一致の数をカウントし、5つ以上ある場合は警告を受け取ります。 実行を中断することはありませんが、モジュールの名前を変更することについて考える価値があることをユーザーに明確にします。



次に、アクションクラスを初期化し、引数として解析に渡します。



 my $actions = Module::Name::Actions.new; my $match_obj = Legal-Module-Name.parse($proposed_module_name, :actions($actions));
      
      







構文解析中に適切なトークンが検出されるたびに、文法はアクションのクラスの適切なメソッドを呼び出します。 私たちの場合、これは解析中に一度発生します。



Perl 5の文法



また、Perl 5では文法を実行できます。 Perl 6に似たソリューションについては、 Regexp :: GrammarsまたはIngyDötNetのPegexの方向を見ることができます。 優れた実装は、JSONの文法の例を含むbrian d foyの第1章「 Mastering Perl 」にあります。



All Articles