RewriteTokens Ver.2

RewriteTokens Ver.2

Yoshida Atsushi (Nanzan University)

1 RewriteTokens Ver.2 とは

RewriteTokens は TEBA の主要なモジュールであり、与えられた字句の書換えルールに従って、 属性付き字句のリストを与える機能を持つ。 RewriteTokens Ver.2 は、最初の RewriteTokens の開発および使用経験に基づき、 新しく設計し直したものである。特徴は以下の通りである。

ここでの最短適合とは、任意の長さの字句列に適合していくときに、 その後に期待される字句と出会ったら、その時点で適合を選択する方法である。 最初の RewriteTokens は最長適合を採用しており、できるだけ長い字句列に適合しようとする。 任意の長さの字句列が過度に適合したときは、バックトラック機能により、 元に戻って適合すべき範囲を調整するので便利であるが、バックトラックに時間がかかることがある。 TEBA では、構文要素を、開始と終了を表す特殊な字句が対で表現し、 その対に対する適合が頻繁に行われる。 開始の字句と終了の字句の間に任意の字句の並びがあることを表現したときに、 最長適合の場合は、「任意の字句」に終了字句が含まれないようにするか、 あるいは適合戦略を変更する指示を入れることで、記述を複雑化させるか、 バックトラックして適合することを期待して実行時間を犠牲にしやすい。 最短適合を採用すると、終了の字句に出会った時点で、適合が終了するので、 素直に「任意の字句」を表現でき、バックトラックも減るので実行時間の無駄も減る。

TEBA の構文解析では、構文要素を開始字句と終了字句の組で表現する。 書換えルールでは、その組であることを示すために、字句変数に識別記号を付加し、 同一の識別記号を持つものを組としている。 しかし、ルールを書くときに他の組と重ならないように識別記号を考える必要がある。 経験上、意味がある名前を付けることは少なく、#1#2 といった書換えルールの意味とは関係のない名前をつけがちである。 また、ルールを見たときにどこが対になっているかはわかりにくく、 書き間違いによって組になるべき字句が別の識別記号を持つなどの間違いを犯しやすい。 さらに、それを見つけるには、慎重に対応関係を確認しながらルールを読んでいく必要があり、 開発に時間がかかりやすい。 そこで、Ver.2 では、対になる字句変数には 開き括弧と閉じ括弧を付随させる書き方を採用した。これにより、 識別記号を書く必要性がないことに加え、 対応する括弧を見つけるエディタの機能を利用することで、対応関係がわかりやすくなっている。

最初の RewriteTokens は、1つのルールを繰り返し適用することはできても、 複数のルールからなるルールセットを繰り返す場合には、 それ専用のインスタンスを用意する必要があり、ルールセットの分断が必要であった。 その結果、繰返しの有無でルールセットを書いているファイルを分割をしたり、 繰返しの中に実際は1回しか書換えが起きないルールが含まれるなど、 保守性や実行効率の観点で問題が多かった。 Ver.2 では、複数のルールに対する繰返しをルールセットの中で明示的に書くことができるので、 ルールセット全体を1つのファイルにまとめることができ、 また、繰返すかどうかを木目細かく設定できるようになった。

プログラミング言語の多くで、同じ記号が別の意味で使われる。例えば、C言語では、 波括弧は複合文を構成する要素であるとともに、 配列の初期値や構造体の定義などを構成する要素としても使われる。 その場合、何を解析しているときの波括弧なのか、 というように文脈を区別しないと、正しく解析できない。最初の RewriteTokens は、 特殊な IN という表記を用いて、 対になる字句の間でのみ字句の型を書換える限定的な機能があるのみで、 その他の状況においては、一度書換えておいてから戻すなど、 様々な工夫が必要であった。 Ver.2 では、文脈を指定し、指定された部分列に対してのみルールを適用できる。 これにより、文脈ごとの解析の切り替えが容易になっている。 加えて、全体に適用しても影響はないものの、 実際には限定された範囲にしか適用されないような書換えルールを、 その範囲のみに適用するようにすることで、実行効率の向上にも利用できる。

プログラムの書換えそのものより、あるパータンに適合した箇所を求めたいときがある。 従来の RewriteTokens では、書換えのみを実現していたので、 取り出したい箇所に印を入れる書換えを行い、その印を探して取り出す操作は 別のツールとして実装する必要があった。 Ver.2 では、着替えルールの置換後の字句列の定義を JSON の形式で変数を参照する データ構造を書くことで、そのルールが適用されたときの変数の値(字句列)を JSON のデータとして取り出すことができる。 これにより、他のツールとの連携などが容易になる。

2 構文

RewriteTokens における書換えルールの構文は以下の通りである。

<ルールセット> ::=  ( <制御構造> | <書換えルール> | <適合ルール> | <ルール読み込み> | <字句マクロ定義> )*
<制御構造> ::= <繰返し適用> | <条件適用> | <文脈適用> | <停止>

<繰返し適用> ::= 'REPEAT' '{' <ルールセット> '}'
<条件適用> ::= 'IF' '{' <ルールセット> '}'
<文脈適用> ::= 'CONTEXT' '{' <文脈字句リスト> '}' '{' <ルールセット> '}'
<停止> ::= 'STOP'

<ルール読み込み> ::= 'INCLUDE' '"' <ファイル名> '"'

<書換えルール> ::= '{' <適合字句リスト> '}' '=>' '{' <置換字句リスト> '}'
<適合ルール> ::= '{' <適合字句リスト> '}' '=>' '[' <変数参照書式> ']'

<適合字句リスト> ::= ( <字句変数> | <変数参照> | <グループ> | '|' )*

<グループ> ::= '[' ( <名前> ':' )? <適合字句リスト> ']' ( '*' | '?' | '!' | '**' )?


<文脈字句リスト> ::= <適合字句リスト> '(' <適合字句リスト> ')' <適合字句リスト>


<字句変数> ::= '('? '$' <名前>? ( '#' <識別記号> )? 
                 ':' ( <型> | <型パターン> ) <テキストパターン>? ')'?

<型パターン> ::= '/' <正規表現> '/'
<テキストパターン> ::= '/' <正規表現> '/'

<置換字句リスト> ::= ( <変数参照> | <字句リテラル> | '[' <置換字句リスト> ']' | <適用ID> )*

<変数参照> ::= '$' <名前> | '$' <名前> ':' <型>
<字句リテラル> ::= '\'' <テキスト> '\'' ':' <型>
<適用ID> ::= '$$'

<変数参照書式> ::= <配列> | <連想配列> | <字句変数>
<配列> ::= '[' <変数参照書式> ( ',' <変数参照書式> )* ']'
<連想配列> ::= '{' <連想組> ( ',' <連想組> )* )? ']'
<連想組> ::= <名前> '=>' ( <変数参照書式> | <文字列リテラル> )

<字句マクロ定義> ::= '@' <マクロ名> '=>' '{' <適合字句リスト> '}'

<名前> ::= <識別子>
<型> ::= <識別子>
<マクロ名> ::= <識別子>
<ファイル名> ::= <ファイルパス>
<文字列リテラル> ::= '"' <文字列> '"'

終端記号については、以下の通りである。

3 属性付き字句

TEBA では、字句を属性付き字句として取り扱い、それの並びである字句列を書換えることで、 構文解析やソースコードの書換えを実現する。 属性付き字句は、字句のテキストに型と識別記号を付与したものであり、例を次に示す。

各字句の先頭の単語が型を示し、 最後の <> の囲みの中が字句のテキストを表現する。 字句のテキストは空文字でも構わない。 型は必須であり、字句の種類を表す文字列である。 異なる種類の字句でも、似たものは1つの種類として扱いたい場合があるので、 類似する種類の字句の型は先頭の文字が一致するように定義されている。 例えば、識別子はすべて ID で始まる型名であり、その中で型に関する識別子は ID_T で始まる識別子になっている。

識別記号は必須ではなく、構文要素の開始と終了を表す字句や括弧の開きと閉じなど、 組になる字句に対して、組を区別できるよう同一の字句が付与される。 例を次に示す。

B_P #B0001 <>
OP_U <->
B_P #B0002 <>
ID_VF <hoge>
E_P #B0002 <>
E_P #B0001 <>

また、慣習として、以下のように型名が割り当てられる。

なお、これらの規則は RewriteTokens の処理には関係せず、 字句列を見やすく処理したいときや、書換えの誤りを見つけやすくするなど、 主に書換え実現時のデバッグを容易にすることを目的としている。

4 書換えルールの書き方

書換えルールの全体(ルールセット)には、以下の4種類の構成要素を記述する。

記述したものは、上の要素から順次、1回ずつ適用されていく。 例えば、字句マクロ定義は、定義がある箇所以降のルールに適用される。 また、ルール読み込みは、その記述がある箇所に展開されたものと同等になる。 また、上記以外に、必要に応じてコメントも記述できる。

4.1 書換えルール

書換えルールは、「適合字句リスト」と「置換字句リスト」から構成される。 適合字句リストは、書換えたい字句の並びに対するパターンであり、 置換字句リストはそのパターンに適合した字句列の部分を置換えとなる字句のリストである。 次に示す例では、適合字句リストとして $a:A $b:B $c:C が、 置換字句リストとして $a '':B_BC $b $c '':E_BC が記述されている。

{ $a:A $b:B $c:C } => { $a '':B_BC $b $c '':E_BC }

適合字句リストは、字句または部分字句列に適合する変数で構成され、 その変数を置換字句リストで参照することで、元の字句または部分字句列を残すことができる。 また、置換字句リストでは、変数ではなく、新しい字句を記述することで、字句の追加が実現できる。 なお、置換字句リストで参照しない変数は名前を省略できる。

4.1.1 適合字句リストにおける変数

適合字句リストでは、字句変数を $変数名:型名 と書く。 ただし、以下のような書き方も行える。

  • $変数名:/型名パターン/ 型名の部分にパターンを指定でき、 そのパターンに適合する型名を持つ字句が適合する。パターンは文字列の正規表現で記述する。 例えば、$x:/ID/ は先頭が ID で始まる型を持つ変数に適合する。 なお、型名の先頭から一致する点に注意すること。
  • $変数名:型名/字句パターン/ と後ろに字句に対するパターンを記述できる。 この場合、指定された型名の字句のうち、 字句そのものが字句パターンに適合するもののみがこの変数に適合する。 字句パターンは文字列の正規表現で記述し、こちらも先頭から一致するものに限る。
  • ($変数名:型名$変数名:型名) は、 同じ識別記号を持つ2つの字句にそれぞれ適合する。 これは、B_PE_P など、対になっている字句に適合したいときに使用する。 丸括弧は、変数と結合した状態で記述されている必要があり、 開き括弧の後ろ、あるいは閉じ括弧の前に空白を入れた場合とは区別される。
  • これらのものは組み合わせが可能であり、 ($変数名:/型パターン//字句パターン/ のようにも記述できる。
  • 変数名は省略可能であり、$:型名 のように書ける。

4.1.2 適合字句リストにおける変数参照

適合字句リストでは、変数参照を書くことができる。 変数参照は $変数名 と書き、 字句変数との表現上の違いは、コロンとそれに続く型の情報がないことである。

変数参照を書く場合は、その変数がそれより前に適合字句リストに出現しており、 かつ、何らかの字句が適合している場合に、 その適合した字句と等しい字句に適合することを意味する。

なお、制限として、1つの字句にのみ適合する。次に示すグループに適合したものを、 変数参照で指定することはできない。使い方の典型例は、次のように、 同じ名前の変数が使われているときに、そのことを指定するときに使用する。

# Example: a + a => a * 2
{ ($bp1:B_P $a:ID_VF $ep1:E_P)
    $sp1:@SP $:OP/\+/ $sp2:@SP
      ($bp2:B_P $a $ep2:E_P) }
=> { $bp1 $a $ep1
     $sp1 '*':OP $sp2
     $bp2 '2':LIN $ep2 }

4.1.3 適合字句リストにおけるグループ

適合字句リストでは、字句のリストを角括弧 [] で囲むことで、グループを記述できる。 グループには以下機能を追加できる。

  • 角括弧の開きを[変数名: と記述することで、その字句リスト全体に変数を割り当てられる。 字句の並びをそのまま置換字句リストで参照するときに、まとめて1つの名前で参照できるのでわかりやすくなる。 また、その場合、角括弧内の変数の名前は省略できる。
  • 角括弧の閉じを]* と記述すると、括弧内の字句リストの 0 回以上の繰返しを意味する。 最短適合の戦略で動作するので、この繰返しは、グループの直後に指定された字句が出現するまで適合し、 グループを抜ける。 ただし、それ以降の字句列に適合しない場合は、バックトラックし、再度、繰返しを進める。
  • 角括弧の閉じを]? と記述すると、括弧内の字句リストの1回以下の繰返しを意味する。 すなわち、その字句リストが存在しないか、1回だけ存在するときに適合する。 最短適合の戦略に基づき、このグループの後ろの字句に適合できる限りは、 このグループに適合しない。グループの後で適合できなくなった場合には、 バックトラックし、グループ内の適合を試みる。
  • 角括弧の閉じを]! と記述すると、括弧内の字句リストに適合した場合は、 パターンマッチに失敗する。 これは、2つの構文要素の間に出現して欲くない要素があることを指定するときに使用する。
  • 角括弧の閉じを ]** と記述すると、括弧内の字句リストの 0 回以上の繰返しを意味する。 ただし、]* とは異なり、最長適合の戦略で動作する。 この繰返しは、できるだけ繰り返しで適合できるところまで進んでから、後続の字句に適合する。 ただし、後続の字句列に適合しない場合はバックトラックし、 繰返しを戻しながら適合できる箇所を求める。 バックトラックが発生しやすいので、必要がない限りは利用は避けるべき。

パターンマッチを失敗させる例は、 ある変数の代入文とその参照文の組をパターンで適合したいときに、 その代入文と参照文の間に、同じ変数への代入文がないことを指定するものである。 この場合、次のように書ける。なお、ここでは参照文は return 文としている。

  [assign:  # 代入文
    ($:B_ST ($:B_P ($:B_P $var:ID_VF $:E_P) $:@SP $:OP/=/ $:@ANY $:E_P) $:@SP $:SC $:E_ST) 
  ]
  $:@SP
  [
    [ # 否定したい代入文
      [ ($:B_ST ($:B_P ($:B_P $var $:E_P) $:@SP $:OP/=/ $:@ANY $:E_P) $:@SP $:SC $:E_ST) ]!
      # または、任意の文
      | ($:B_ST $:@ANY $:E_ST)
    ] 
    $:@SP 
  ]* # それらの繰返し

  # return 文 (代入文で代入される変数の値を返すもの)
  [return: ($:B_ST $:RE_JP $:@SP ($:B_P $var $:E_P) $:@SP $:SC $:E_ST) ]

ここでは、選択を使用して、否定する代入文と任意の代入文のどちらかの繰返しとしている。 選択は、左側から評価されるので、代入文があれば否定されて、適合に失敗する。 代入文ではない場合には、任意の文が適合するので、適合は継続する。

4.1.4 適合字句リストにおける選択

複数の選択肢を記述するときは、適合字句リスト内を | で区切る。 グループ内で使用し、区切られたいずれかの部分に適合することを意味する。 ただし、厳密には、区切られた各リストを左から順に適合するかどうか調べ、 最初に適合したものがそのグループ全体に適合したものとなる。 よって、適合した字句リストより右に出てくるものに適合可能なものあっても無視される。 ただし、選択した結果、選択のグループ以降の適合が失敗した場合には、 バックトラックを行い、さらに右の選択肢への適合を試みる。

4.1.5 置換字句リスト

置換字句リストは、基本的には次の2つを書く。

  • 変数の参照として $変数名
  • 字句の挿入として '字句':型名

これらには、いくつかの変形がある。

  • 変数を参照するときに、$変数名:型名 と型名を付与することで、その字句の型名を置換えることができる。 なお、変数がグループにより複数の字句を参照しているときは、その字句を結合して1つの字句に変換し、 指定された型名を付与する。
  • ($変数名$変数名) の組、あるいは、('字句':型名'字句':型名) の組のように 丸括弧をつけることで、それらの字句には同じ識別記号が割り当てられる。

4.1.6 置換字句リストにおける字句の結合と適用ID

置換後に複数の字句を1つの字句に置き換えたい場合がある。 その場合は、結合したい字句を [] で囲う。 なお、結合後の字句の型は先頭の字句のものになる。 もし先頭の字句が目的の字句ではない場合には、空の字句 '':目的の型名'' を 先頭に挿入すればよい。

文字を結合したいときの目的のひとつは、新しい変数の導入である。 変数名を適用ごとに変える必要があるときは、適用ID $$ を変数字句と結合させる。 例えば、新しい変数を次のように表現する。

  [ 'TMP':ID_VF $$ ]

これにより、TMP1, TMP2 のような数字が付与された変数名が、 ルールが適用されるたびに生成される。なお、すべてのルールごとに IDが変化するので、1から始まる連番にしたいといった要求は実現できない。 また、$$ は内部では __APPLY_ID <数字> という字句に置き換わる。

4.2 字句マクロ定義

適合字句リストを記述するときに、その部分リストに名前をつけて、グループとして参照できるマクロ機能がある。 字句マクロ定義は次のように書く。

@マクロ名 => { 適合字句リスト }

また、マクロを参照するときは $変数名:@マクロ名と記述する。マクロ名と型名を区別するために、 参照の際にも @ が必要な点に注意が必要である。 なお、RewriteTokens の内部では、マクロの参照は [変数名: 適合字句リスト ] と展開してから処理される。

4.3 制御構造

制御構造として、以下の4つを記述できる。

4.3.1 繰返し適用

繰返し適用は REPEAT { ルールセット } と記述し、 ルールセットによって書換えが行われなくなるまで書換えを続ける。 ルールセットの定義によっては、無限ループになる可能性がある。 なお、ルールセットを記述できるので、繰返しの中でさらに繰返しなどの制御構造を書くことも可能である。

4.3.2 条件適用

条件適用は、IF { ルールセット } と記述し、 その直前の書換えルールにおいて書換えが起きたときのみに、ルールセットを実行する。 複数のルールで、1つの書換え処理を実現しているときに、最初のルールで書換えが起きなければ、 後のルールで書換えが発生しないといった状況では、最初のルールで書換えたときのみ後のルールを 適用させることで、無駄な処理を減らすことができる。 なお、意味がわかりやすいように IF の代わりに IF_MATCHED と記述してもよい。

4.3.3 文脈適用

文脈適用は、CONTEXT { 適合字句リスト } {ルールセット} と記述する。 適合字句リストに適合した字句の並びのうち、丸括弧で囲まれた範囲に対してのみ、 ルールセットを適用する。 主に特定の文脈の中での字句の並びを書換えたいときに使用する。 また、ある範囲の中でのみ複数の書換えが起きる場合に使用すると、 無関係な部分で字句の検索を減らせるので、実行効率が良くなる。 なお、丸括弧は、単体のものであり、対を表す字句変数に用いる丸括弧とは区別する。 よって、丸括弧と字句変数の間には空白が必要である。

4.3.4 停止

停止は STOP と記述し、この命令がある位置で、実行が停止する。 これは、デバッグ時に、どこまでが正しく動いているかを確認するときに使用する。

4.4 適合ルール

適合字句リストに適合したときに、適合した変数の値を取り出す方法として、適合ルールがある。 書換えルールとの意味的な違いは、書換えを行わないことと、置換字句リストの代わりに 変数参照書式を書くことである。変数参照書式は、JSON 形式で取り出すことを意図し、 適合ルールを適用した結果として、JSON 化が可能な木構造のオブジェクトを得られる。

書換えルールとの表記の違いは、=> の右側が、波括弧 {} で囲まれるか、 角括弧 [] で囲まれるかである。 各括弧を採用した理由は、適合ルールで得られるオブジェクトが「リスト」になることである。 適合ルールは、複数の箇所に適合する可能性があり、 それぞれの箇所ごとにオブジェクトが生成される。 なお、この角括弧は、表記上、意味を考慮して採用しただけで、 次に説明する変数参照書式には含まれない。 よって、角括弧内には変数参照書式を1つしか記述できない点に注意する必要がある。

4.4.1 変数参照書式

基本的には、Perl のリスト(配列)とハッシュ(連想配列)と同じ書き方であるが、 値として、字句変数の参照と文字列リテラルを記述できる。 先に述べたように、ルールの右側の角括弧内には変数参照書式は1つしか記述できない。 よって、複数の値またはオブジェクトを扱う場合には、リストを明示的に書く必要がある。 適合ルールの例を以下に示す。

# 変数 $x, $y を取り出す。2つの値を扱うためにリスト [$x, $y] として表現。
{ $x:X $y:Y } => [ [ $x, $y ] ]  # 

# 少し複雑なオブジェクトの例
{ $a:A $b:B, $c:C } => [ 
    {
      name => "Rule ABC",
      a => $a,
      bc => [ $b, $c ]
    }
  ]

適合するすべての箇所について、それぞれ単独のオブジェクトが生成され、 最終的にそのリストが作られる。このとき、字句変数の参照は、 適合時にその字句変数に代入されている字句列と、その開始と終了の位置からなる オブジェクトになる。 そのオブジェクトの書式は次の通りである。

{
  t => [ <字句リスト> ],
  r => [ <開始位置>, <終了位置> ]
}

開始位置と終了位置は、字句リストの先頭を 0 番目として数えた位置である。 なお、適合した時点の位置なので、そのあとに書換えを行うとずれが生じる可能性がある。 よって、位置の情報を使いたいときは、すべての書換えが終了したあとに使用する必要がある。

4.4.2 オブジェクトの取り出しと JSON 化

オブジェクトを取り出すときは、RewriteTokens2 のインスタンスから、 メソッド vars を用いて取り出す。 このオブジェクトは2段階のリスト構造になっている。 まず、複数の適合ルールを記述した場合に対応するために、 適合ルールごとの結果が格納されたリストになっている。 適合ルールごとの結果は、適合した箇所ごとのオブジェクトのリストになっている。 適合箇所ごとのオブジェクトは、変数参照書式で指定したものになる。 また、JSON化は JSON モジュールを用いて変換する。 詳細はメソッドの説明で確認すること。

4.5 ルール読み込み

ルール読み込みは、INCLUDE "ファイル名 と記述する。 この命令が記述された箇所が、指定されたファイル名のファイルの内容に置換えられる。 読み込むファイルの場所は、RewriteTokens のメソッド include_path で設定する。 コロンで区切ることで、複数のディレクトリを指定できる。 設定しない場合は、標準でカレントディレクトリから読み込む。 なお、ファイル名が絶対パス(“/” で始まるパス)で指定されていた場合は、 そのパスのファイルを読み込む。

ルール読み込みを使うことで、以下のことが実現できる。

4.6 コメント

ルールセット内で、次の2通りの記述がコメントとして扱われる。

5 RewriteTokens クラスの使い方

以下、RewriteTokens の主要メソッドについて説明する。ただし、詳細については、 RewriteTokens クラスのソースコードそのもので確認してもらいたい。

5.1 new

RewriteTokens を用いるには、まず、new メソッドでインスタンスを生成する。 引数として、連想配列の参照を受け取り、インスタンスのフィールドとして設定できる。 返り値は、生成したインスタンスの参照である。

5.2 include_path

RewriteTokens のインスタンスに対して、ルール読み込みでファイルを検索するパスを設定する。 引数は文字列で、複数のパスを指定する場合には、コロンで区切って記述する。 返り値は、パスを設定したインスタンスの参照である。

5.3 rule

RewriteTokens のインスタンスに対して、ルールセットを設定する。 引数はルールセットを記述した文字列である。 返り値は、ルールセットが設定されたインスタンスの参照である。

ルールセットを設定すると、ルールセットを構文解析し、字句の書換えのための 内部プログラムの生成まで行う。

5.4 apply

ルールセットを設定した RewriteTokens のインスタンスに対して、 字句リストを渡して、書換えを行う。 引数は、字句リストへの参照であり、その字句リストが書き変わる。 返り値は、ルールセットが設定されたインスタンスの参照である。 なお、字句リストは改行文字を含まない字句リストにする必要がある。

書換えた箇所の数は、apply を実行したときにインスタンスに記録されるので、 count で参照できる。

RewriteTokens を使って書換えするときの典型的な書き方は次の通りである。


my @token_list = <>; # reads a token list from stdin or a file.

chomp @token_list;   # removes the newlines at the ends of tokens.

my $path = "dokoka/dokoka/dokodayo";         # the path where INCLUDE searches files
my $rule = q( { $x:X $y:Y } => { $y $x } );  # an example of rule

my $rt = RewriteTokens->new()        # create an instance
             ->include_path($path)   # set the include path if you need.
             ->rule($rule)           # set the rules to the insntace
             ->apply(\@token_list);  # apply the rules to @token_list

print "Number of Replacement:",  $rt->count, "\n";

5.5 count

apply を適用したときに書換えた箇所の数を返す。 使用例は、apply の説明を参照すること。

5.6 vars

適合ルールの結果を受け取るときは、vars を使う。 返り値は、すべての適合ルールについて、それぞれの結果が入ったリストである。 各適合ルールごとの結果は、すべての適合箇所ごとの結果のリストである。 適合ルールが1つしかない場合も、これに従う。 例えば、適合ルールが2つあり、それぞれが2箇所と3箇所に適合したとすると、 次の構造になる。

  [
    [ 適合ルール1の1箇所目のオブジェクト, 適合ルール1の2箇所目のオブジェクト ],
    [ 適合ルール2の1箇所目のオブジェクト, 適合ルール1の2箇所目のオブジェクト,
      適合ルール1の3箇所目のオブジェクト]
  ]

得られるオブジェクトはリストとハッシュ、文字列で構成される木を構成するので、 JSON に変換可能である。JSON モジュールを使うと次のように変換できる。


# ... 省略

my $rt = RewriteTokens->new()         # create an instance
             ->include_path($path)    # set the include path if you need.
             ->rule($rule)            # set the rules to the insntace
             ->apply(\@token_list);   # apply the rules to @token_list

my $rep = $rt->vars;  # a list of variable sets of matched regions.

my $rep_json = JSON->new->pretty->encode($rep);  # convert to JSON

print "Matched variables (JSON):",  $rep_json, "\n";

5.7 debug_mode

RewriteTokens をデバッグモードに切り替えるクラスメソッドである。 デバッグモードは、RewriteTokens は次のように動作する。

このうち、ルールセットの構文検査では、括弧の対応関係などを検査する。 デバッグモードではないときは、対応関係を検査しないので、 不整合があると実行時にエラーが出る。このとき、エラーメッセージからは 何が原因であるかの推測は難しい。

デバッグ用の出力は RewriteTokens の開発用のものになっているので、 不可解なエラーが出たときは開発者に相談すること。

返り値はモードが切り替わったインスタンスである。 例えば、RewriteTokens->new()->debug_mode() で、 デバッグモードが有効になったインスタンスを生成できる。

5.8 graph_mode

RewriteTokens が解釈したルールを画像グラフとして出力する。 GraphViz を使用して生成している。 なお、グラフに含まれるのは書換え規則全体の流れと、 書換えルールの適合字句リストのパターンである。 RewriteTokens は、ここで生成されるグラフに基づいて適合箇所を求めている。 返り値はモードが切り替わったインスタンスである。

文責: 吉田 敦
Contact: Yoshida Atsushi