[pod] [xml]

名前

Parse::RecDescent - 再帰下降パーサの生成 (Generate Recursive-Descent Parsers)

バージョン

This document describes version 1.94 of Parse::RecDescent, released April 9, 2003.

このドキュメントは、2003年4月9日にリリースされた Parse::RecDescentのバージョン1.94について述べたものである。

概要

 use Parse::RecDescent;
 # $grammarの仕様書からパーサを生成
	 $parser = new Parse::RecDescent ($grammar);
 # $othergrammarの仕様書からパーサを生成
	 $anotherparser = new Parse::RecDescent ($othergrammar);
 # 規則'startrule'($grammar内で定義されなければならない)
 # を用いて$textを解析:
	$parser->startrule($text);
 # 規則'otherrule'(これも$grammar内で定義されなければならない)
 # を用いて$textを解析:
	 $parser->otherrule($text);
 # 全般的なトークン前置子のパターンを変更
 # (デフォルトは'\s*'):
	$Parse::RecDescent::skip = '[ \t]+';
 # $newgrammarで定義されたプロダクションを使って既存規則の
 # プロダクションを置き換える(あるいは新しいものを作成):
	$parser->Replace($newgrammar);
 # $moregrammarで定義されたプロダクションを加えて
 # 既存規則を拡張する(あるいは新しいものを作成)
	$parser->Extend($moregrammar);
 # グローバルなフラグ(-sでのコマンドライン引数として便利):
	$::RD_ERRORS	   # 未定義でなければ、致命的エラーを報告
	$::RD_WARN	   # 未定義でなければ、致命的でない問題も報告
	$::RD_HINT	   # 定義されていれば、回復方法も示唆
	$::RD_TRACE	   # 定義されていれば、パーサの振る舞いもトレース
	$::RD_AUTOSTUB	   # 定義されていれば、未定義の規則用に"スタブ"を生成
	$::RD_AUTOACTION   # 定義されていれば、プロダクションに指定されたアクション追加

説明

概観

Parse::RecDescent incrementally generates top-down recursive-descent text parsers from simple yacc-like grammar specifications. It provides:

Parse::RecDescentは、単純なyacc風の文法仕様から、 下向きの再帰下降パーサを段階的に生成する。提供される機能は:

Parse::RecDescentの利用

Parser objects are created by calling Parse::RecDescent::new, passing in a grammar specification (see the following subsections). If the grammar is correct, new returns a blessed reference which can then be used to initiate parsing through any rule specified in the original grammar. A typical sequence looks like this:

Parse::RecDescent::newを呼び出すと、文法仕様を 通してパーサオブジェクトが生成される(続くサブセクションを参照)。 文法が正しいものであれば、newはblessされたリファレンスを返す。 その後、このリファレンスは元の文法で指定された規則を通じて解析を開始 するのに利用できる。典型的な流れは次のようになる:

	$grammar = q {
			# ここに文法仕様
		     };
	$parser = new Parse::RecDescent ($grammar) or die "Bad grammar!\n";
	# $textの獲得
	defined $parser->startrule($text) or print "Bad text!\n";

The rule through which parsing is initiated must be explicitly defined in the grammar (i.e. for the above example, the grammar must include a rule of the form: "startrule: <subrules>".

解析開始の際に用いられる規則は、文法において明示的に定義されなければ ならない(つまり上の例でいうと、この文法は次のような形式の規則を 含まなければならない:"startrule: <subrules>")。

If the starting rule succeeds, its value (see below) is returned. Failure to generate the original parser or failure to match a text is indicated by returning undef. Note that it's easy to set up grammars that can succeed, but which return a value of 0, "0", or "". So don't be tempted to write:

開始の規則が成功すると、その値(下記参照)が返される。 元になるパーサの生成に失敗したり、テキスト照合に失敗すると、 undefが返されることによって示される。成功する文法を用意するのは 簡単だが、それは0、"0"、あるいは""という値を返すことに注意。だから、 このような書き方をしてはいけない:

	$parser->startrule($text) or print "Bad text!\n";

Normally, the parser has no effect on the original text. So in the previous example the value of $text would be unchanged after having been parsed.

通常、パーサは元のテキストに何ら影響を与えない。それゆえ、先の 例では、$textの値は解析後も変化しない。

If, however, the text to be matched is passed by reference:

しかしながら、照合させるテキストをリファレンスで渡した場合:

	$parser->startrule(\$text)

then any text which was consumed during the match will be removed from the start of $text.

照合時に消費されたテキストは$textのはじめから取り除かれるだろう。

規則 (Rules)

In the grammar from which the parser is built, rules are specified by giving an identifier (which must satisfy /[A-Za-z]\w*/), followed by a colon on the same line, followed by one or more productions, separated by single vertical bars. The layout of the productions is entirely free-format:

パーサ構築に用いられる文法中で、識別子(/[A-Za-z]\w*/を満たさなければ ならない)、次いで同一行にコロン、次いで単一の縦棒で区切られた 一つ以上のプロダクション(production)を与えることによって規則は 設定される。プロダクションのレイアウトは完全に自由形式である:

	rule1:	production1
	     |  production2 |
		production3 | production4

At any point in the grammar previously defined rules may be extended with additional productions. This is achieved by redeclaring the rule with the new productions. Thus:

文法の任意の場所で、前に定義した規則を追加のプロダクションでもって 拡張することができる。これは新しいプロダクションの規則を再宣言する ことによって達成される。すなわち:

	rule1: a | b | c
	rule2: d | e | f
	rule1: g | h

is exactly equivalent to:

は次のものと正確に等価である:

	rule1: a | b | c | g | h
	rule2: d | e | f

Each production in a rule consists of zero or more items, each of which may be either: the name of another rule to be matched (a "subrule"), a pattern or string literal to be matched directly (a "token"), a block of Perl code to be executed (an "action"), a special instruction to the parser (a "directive"), or a standard Perl comment (which is ignored).

規則内のプロダクションはそれぞれ、0個以上のアイテムを構成する。 アイテムは次のいずれかである:照合されるべき別規則の名前("サブ規則")、 直接照合される正規表現パターンあるいは文字列リテラル("トークン")、 実行されるPerlコードのブロック("アクション")、パーサに対する特別な 指示("ディレクティブ")、あるいは標準的なPerlコメント(無視される)。

A rule matches a text if one of its productions matches. A production matches if each of its items match consecutive substrings of the text. The productions of a rule being matched are tried in the same order that they appear in the original grammar, and the first matching production terminates the match attempt (successfully). If all productions are tried and none matches, the match attempt fails.

ある規則のプロダクションのどれか一つにマッチすれば、あるテキストは その規則にマッチしたことになる。あるプロダクションのアイテム全てが、 そのテキストの連続する文字列にマッチすれば、そのプロダクションは マッチしたことになる。マッチした規則のプロダクションは、元の文法に 現れたのと同じ順番で試される。そして最初にマッチしたプロダクションに よって照合の試みは終了する(成功)。もし全てのプロダクションが試みられ、 かつ、マッチしなければ、照合の試みは失敗となる。

Note that this behaviour is quite different from the "prefer the longer match" behaviour of yacc. For example, if yacc were parsing the rule:

この振る舞いは、yaccの”最長マッチ指向”(prefer the longer match) とは全く違うので注意すること。

	seq : 'A' 'B'
	    | 'A' 'B' 'C'

upon matching "AB" it would look ahead to see if a 'C' is next and, if so, will match the second production in preference to the first. In other words, yacc effectively tries all the productions of a rule breadth-first in parallel, and selects the "best" match, where "best" means longest (note that this is a gross simplification of the true behaviour of yacc but it will do for our purposes).

"AB"にマッチした時、yaccは'C'が次に来るかどうか調べるために先読みをする。 そしてその通りであったら、最初のプロダクションではなく二番目の プロダクションにマッチすることになる。言い換えると、yaccは 幅優先で並列に規則のプロダクションを全て試みる。そして"best"な マッチを選択する。ここで"best"とは、最長を意味する(これはyaccの 振る舞いをあまりに単純化してしまっているが、我々の目的には適っている)。

In contrast, Parse::RecDescent tries each production depth-first in sequence, and selects the "best" match, where "best" means first. This is the fundamental difference between "bottom-up" and "recursive descent" parsing.

対照的に、Parse::RecDescentは深さ優先で連続的にそれぞれの プロダクションを試みる。そして"best"なマッチを選択する。ここで "best"とは、最初のプロダクションということである。これが、 ”上向き”("bottom-up")パーサと”再帰下降”("recursive descent") パーサの根本的な違いである。

Each successfully matched item in a production is assigned a value, which can be accessed in subsequent actions within the same production (or, in some cases, as the return value of a successful subrule call). Unsuccessful items don't have an associated value, since the failure of an item causes the entire surrounding production to immediately fail. The following sections describe the various types of items and their success values.

プロダクション内で照合に成功したアイテムはそれぞれ、ある値が割り当て られる。この値は同じプロダクション内の(場合によっては成功したサブ規則 の戻り値として)その後に続くアクションからアクセス可能である。 照合に成功しなかったアイテムは関連づけられた値を持たない。というのも、 アイテムの失敗は、それを取り囲んでいるプロダクション全体を直ちに失敗 させるためである。続くセクションでは、様々なアイテムのタイプと、その 成功時の値について記述する。

サブ規則 (Subrules)

A subrule which appears in a production is an instruction to the parser to attempt to match the named rule at that point in the text being parsed. If the named subrule is not defined when requested the production containing it immediately fails (unless it was "autostubbed" - see Autostubbing).

プロダクション内で現れるサブ規則は、その時点で解析されているテキストに 対して、その名前が付けられた規則を照合するようパーサを導く。 要求があったのにその名前のサブ規則が定義されていない場合、そのサブ規則を 含むプロダクションは直ちに失敗する("オートスタブされて"いない限り - オートスタブ (Autostubbing)を参照)。

A rule may (recursively) call itself as a subrule, but not as the left-most item in any of its productions (since such recursions are usually non-terminating).

ある規則は自分自身をサブ規則として(再帰的に)呼び出すかも知れない。 しかし、プロダクション内の最左端のアイテムとして呼ばれるのではない (なぜならそのような再帰は通常、非終端であるから)。

The value associated with a subrule is the value associated with its $return variable (see "Actions" below), or with the last successfully matched item in the subrule match.

サブ規則に関連づけられた値とは、その$return変数に関連づけられた 値のことである(後述の"アクション (Actions)"を参照)。あるいは、サブ規則の照合 において、最後に成功したアイテムと関連づけられた値である。

Subrules may also be specified with a trailing repetition specifier, indicating that they are to be (greedily) matched the specified number of times. The available specifiers are:

また、サブ規則はその後ろに、反復指定子が設定されているかもしれない。 この指定子は、指定した回数だけサブ規則が(貪欲に)マッチされる必要が あることを示している。利用可能な指定子は:

		subrule(?)	# 1あるいは0回マッチ
		subrule(s)	# 1回以上マッチ
		subrule(s?)	# 0回以上マッチ
		subrule(N)	# 正確にN回マッチ(Nは整数で N > 0)
		subrule(N..M)	# N〜M回マッチ
		subrule(..M)	# 1〜M回マッチ
		subrule(N..)	# 少なくともN回はマッチ

Repeated subrules keep matching until either the subrule fails to match, or it has matched the minimal number of times but fails to consume any of the parsed text (this second condition prevents the subrule matching forever in some cases).

反復サブ規則は、そのサブ規則が照合に失敗するか、最小回数は マッチしたがパースされたテキストのどこかで消費(consume)に 失敗するかのどちらかになるまで、照合を続ける(この二番目の条件によ り、ある場合で生じるサブルールが永久に照合を行うことを防いでいる)。

Since a repeated subrule may match many instances of the subrule itself, the value associated with it is not a simple scalar, but rather a reference to a list of scalars, each of which is the value associated with one of the individual subrule matches. In other words in the rule:

反復サブ規則は、サブ規則それ自身のインスタンスの多くを照合するかも しれないので、そのサブ規則に関連する値は単純なスカラーではなく、 リストのリファレンスとなる。このリストはそれぞれ、個々のサブ規則の マッチ一つひとつと関連する値である。つまり規則において:

		program: statement(s)

the value associated with the repeated subrule "statement(s)" is a reference to an array containing the values matched by each call to the individual subrule "statement".

反復サブ規則"statement(s)"に関連づけられた値は、個々のサブ規則"statement" の呼び出し毎にマッチした値を含んだ配列へのリファレンスである。

Repetition modifieres may include a separator pattern:

反復修飾子は区切りパターンを含むかも知れない。

		program: statement(s /;/)

specifying some sequence of characters to be skipped between each repetition. This is really just a shorthand for the <leftop:...> directive (see below).

これは反復するサブ規則間でスキップされるキャラクタの連なりを指定している。 これはまさに<leftop:...>ディレクティブ(後述を参照)の略記に 他ならない。

トークン (Tokens)

If a quote-delimited string or a Perl regex appears in a production, the parser attempts to match that string or pattern at that point in the text. For example:

もしプロダクション内にクォートで区切られた文字列か、Perlの正規表現が 現れたなら、パーサはテキストのその時点で、その文字列ないしは 正規表現パターンを照合しようと試みる:

		typedef: "typedef" typename identifier ';'
		identifier: /[A-Za-z_][A-Za-z0-9_]*/

As in regular Perl, a single quoted string is uninterpolated, whilst a double-quoted string or a pattern is interpolated (at the time of matching, not when the parser is constructed). Hence, it is possible to define rules in which tokens can be set at run-time:

正規のPerlでは、シングルクォートで囲まれた文字列は展開されない。他方、 ダブルクォートで囲まれた文字列や正規表現パターンは展開される(これは 照合時の話であって、パーサが構築される時の話ではない)。それゆえ、 実行時にトークンをセットしながら、規則を定義することが可能である。

		typedef: "$::typedefkeyword" typename identifier ';'
		identifier: /$::identpat/

Note that, since each rule is implemented inside a special namespace belonging to its parser, it is necessary to explicitly quantify variables from the main package.

注意して欲しいのだが、全ての規則は、パーサに属する固有の名前空間の内部で 実装されているので、mainパッケージの変数であることを明示的に指定する 必要がある。

Regex tokens can be specified using just slashes as delimiters or with the explicit m<delimiter>......<delimiter> syntax:

正規表現トークンは、デリミタとしてスラッシュを使って指定することができる。 あるいは明示的にm<delimiter>......<delimiter>構文が使える:

		typedef: "typedef" typename identifier ';'
		typename: /[A-Za-z_][A-Za-z0-9_]*/
		identifier: m{[A-Za-z_][A-Za-z0-9_]*}

A regex of either type can also have any valid trailing parameter(s) (that is, any of [cgimsox]):

どちらのタイプの正規表現も、その後ろに妥当なパラメータ([cgimsox]で複数可) を持つことができる:

		typedef: "typedef" typename identifier ';'
		identifier: / [a-z_] 		# 最初はアルファベットかアンダーバー
			      [a-z0-9_]*	# 次からは数字もOK
			    /ix			# 大文字小文字の区別/スペース/コメント を無視

The value associated with any successfully matched token is a string containing the actual text which was matched by the token.

マッチに成功したトークンに関連づけられる値とは、トークンによって照合された 実際のテキストを含んだ文字列である。

It is important to remember that, since each grammar is specified in a Perl string, all instances of the universal escape character '\' within a grammar must be "doubled", so that they interpolate to single '\'s when the string is compiled. For example, to use the grammar:

次のことを覚えておくべきである。それぞれの文法はPerlの文字列で指定されて いるので、文法に含まれる一般的エスケープキャラクタ'\'の表記は全て"二重"に しなければならない。こうすれば、その文字列がコンパイルされる時に、単一の '\'に展開される。例えば次のような文法を利用するなら:

		word:	    /\S+/ | backslash
		line:	    prefix word(s) "\n"
		backslash:  '\\'

the following code is required:

以下のコードにする必要がある:

		$parser = new Parse::RecDescent (q{
			word:	    /\\S+/ | backslash
			line:	    prefix word(s) "\\n"
			backslash:  '\\\\'
		});

終端記号の区切り (Terminal Separators)

For the purpose of matching, each terminal in a production is considered to be preceded by a "prefix" - a pattern which must be matched before a token match is attempted. By default, the prefix is optional whitespace (which always matches, at least trivially), but this default may be reset in any production.

照合の目的からすると、プロダクション内の全ての終端記号は"前置子"が 前に来なければならないと考えられる。- すなわちトークンに対する照合が 試みられる前にマッチしなければならないパターンである。デフォルトでは この前置子は任意の空白である(少なくとも自明であるが、これは常に マッチする)。しかしこの既定値は任意のプロダクションで再設定できる。

The variable $Parse::RecDescent::skip stores the universal prefix, which is the default for all terminal matches in all parsers built with Parse::RecDescent.

変数$Parse::RecDescent::skipは全般的な前置子を保持する。 Parse::RecDescentで構築された全てのパーサにおいて、 全終端記号に対する照合のデフォルトはこの前置子になる。

The prefix for an individual production can be altered by using the <skip:...> directive (see below).

個々のプロダクションに対する前置子は、<skip:...> ディレクティブを利用して変更することができる(後述箇所を参考)。

アクション (Actions)

An action is a block of Perl code which is to be executed (as the block of a do statement) when the parser reaches that point in a production. The action executes within a special namespace belonging to the active parser, so care must be taken in correctly qualifying variable names (see also Start-up Actions below).

アクションはPerlコードのブロックである。プロダクション内でパーサが この部分に到達すると、このPerlコードは(doステートメントブッロク の如く)実行される。このアクションは、実際に動作しているパーサに 属する固有の名前空間内で実行される。よって、正しく変数名を指定する ように注意しなければならない(後述の開始アクション (Start-up Actions)も参照)。

The action is considered to succeed if the final value of the block is defined (that is, if the implied do statement evaluates to a defined value - even one which would be treated as "false"). Note that the value associated with a successful action is also the final value in the block.

アクションは、そのブロックの最終的な値が定義されたとき(すなわち内包 されたdoステートメントがある定義値 -- 偽として扱われたとしても -- を評価した場合)、成功したと考えられる。注意しなければならないのは、 成功したアクションに関連付けられる値もまた、そのブロック内の最終値で あるということだ。

An action will fail if its last evaluated value is undef. This is surprisingly easy to accomplish by accident. For instance, here's an infuriating case of an action that makes its production fail, but only when debugging isn't activated:

最後に評価された値がundefの場合、アクションは失敗に終わる。これは ふとした弾みで驚くほど簡単に起こる。例えばこれは、このアクションのある プロダクションを失敗させる劇的なケースである。ただしデバッグモードが 有効いなっていない時にのみ生じるのだが:

	description: name rank serial_number
			{ print "Got $item[2] $item[1] ($item[3])\n"
				if $::debugging
			}

If $debugging is false, no statement in the block is executed, so the final value is undef, and the entire production fails. The solution is:

もし$debuggingが偽であるなら、ブロック内のステートメントは実行されない。 その結果、最終的な値はundefとなり、プロダクション全体が失敗する。解決策は:

	description: name rank serial_number
			{ print "Got $item[2] $item[1] ($item[3])\n"
				if $::debugging;
			  1;
			}

Within an action, a number of useful parse-time variables are available in the special parser namespace (there are other variables also accessible, but meddling with them will probably just break your parser. As a general rule, if you avoid referring to unqualified variables - especially those starting with an underscore - inside an action, things should be okay):

アクション内では、パース実行時の有用な変数の多くは、そのパーサの特別な名前 空間を使って利用できる(他にもアクセス可能な変数はある。だがそれらの変数を いじくりまわすとパーサを壊してしまいかねない。一般的なルールとして、 アクション内では修飾されていない変数 - 殊に、アンダーバーで始まるもの - を 参照するのを回避しておけば、万事うまくいくであろう)。:

Warning: the parser relies on the information in the various this... objects in some non-obvious ways. Tinkering with the other members of these objects will probably cause Bad Things to happen, unless you really know what you're doing. The only exception to this advice is that the use of $this...->{local} is always safe.

警告:パーサは、不明瞭ではるが、様々なthis...オブジェクトの 情報に依存している。これらオブジェクトの他のメンバをへたに弄ると、 十中八九、良くないことが起こるだろう。自分のやっていることを本当に 理解していない限り。この忠告に対する唯一の例外は、 $this...->{local} の利用が常に安全であるということだ。

開始アクション (Start-up Actions)

Any actions which appear before the first rule definition in a grammar are treated as "start-up" actions. Each such action is stripped of its outermost brackets and then evaluated (in the parser's special namespace) just before the rules of the grammar are first compiled.

文法内において最初の規則の定義の前に現れたアクションは、 "開始"アクションとして扱われる。このようなアクションは全て、 文法の規則が最初にコンパイルされる前に(パーサ固有の名前空間で) 外側のブラケットが取り除かれてから評価される。

The main use of start-up actions is to declare local variables within the parser's special namespace:

開始アクションの主要な使い道は、パーサの固有の名前空間内で ローカル変数を宣言することにある:

        { my $lastitem = '???'; }
        list: item(s)   { $return = $lastitem }
        item: book      { $lastitem = 'book'; }
              bell      { $lastitem = 'bell'; }
              candle    { $lastitem = 'candle'; }

but start-up actions can be used to execute any valid Perl code within a parser's special namespace.

しかし開始アクションは、パーサ固有の名前空間内で、どんな正しい Perlコードでも実行することが出来る。

Start-up actions can appear within a grammar extension or replacement (that is, a partial grammar installed via Parse::RecDescent::Extend() or Parse::RecDescent::Replace() - see Incremental Parsing), and will be executed before the new grammar is installed. Note, however, that a particular start-up action is only ever executed once.

開始アクションは、文法の拡張や置換(Parse::RecDescent::Extend()Parse::RecDescent::Replace()を通じて一部の文法をインストールすること。 増加解析 (Incremental Parsing)を参照)内に出現することができる。そして、その 新しい文法がインストールされる前に実行される。しかし、注意して欲しいのは、 その開始アクションは一度だけ実行されるということだ。

オートアクション (Autoactions)

It is sometimes desirable to be able to specify a default action to be taken at the end of every production (for example, in order to easily build a parse tree). If the variable $::RD_AUTOACTION is defined when Parse::RecDescent::new() is called, the contents of that variable are treated as a specification of an action which is to appended to each production in the corresponding grammar. So, for example, to construct a simple parse tree:

プロダクションの終わり毎に、デフォルトで実行されるアクションを 指定したいと思うことがある(例えば、解析木を簡単に構築するためとか)。 Parse::RecDescent::new()が呼び出される際、変数$::RD_AUTOACTIONが 定義されていると、その変数の内容は対応する文法の各プロダクションに 追加されるアクションの指定として扱われる。だから例えば、単純な構文木を 構築するために:

    $::RD_AUTOACTION = q { [@item] };
    parser = new Parse::RecDescent (q{
        expression: and_expr '||' expression | and_expr
        and_expr:   not_expr '&&' and_expr   | not_expr
        not_expr:   '!' brack_expr           | brack_expr
        brack_expr: '(' expression ')'       | identifier
        identifier: /[a-z]+/i
        });

which is equivalent to:

これは次と等価だ:

    parser = new Parse::RecDescent (q{
        expression: and_expr '||' expression
                        { [@item] }
                  | and_expr
                        { [@item] }
        and_expr:   not_expr '&&' and_expr
                        { [@item] }
                |   not_expr
                        { [@item] }
        not_expr:   '!' brack_expr
                        { [@item] }
                |   brack_expr
                        { [@item] }
        brack_expr: '(' expression ')'
                        { [@item] }
                  | identifier
                        { [@item] }
        identifier: /[a-z]+/i
                        { [@item] }
        });

Alternatively, we could take an object-oriented approach, use different classes for each node (and also eliminating redundant intermediate nodes):

これとは別に、オブジェクト指向なアプローチとして、それぞれのノードに 対して様々なクラスを利用することができる(そしてまた、余計な中間ノード を選り分けを行うことも):

    $::RD_AUTOACTION = q
      { $#item==1 ? $item[1] : new ${"$item[0]_node"} (@item[1..$#item]) };
    parser = new Parse::RecDescent (q{
        expression: and_expr '||' expression | and_expr
        and_expr:   not_expr '&&' and_expr   | not_expr
        not_expr:   '!' brack_expr           | brack_expr
        brack_expr: '(' expression ')'       | identifier
        identifier: /[a-z]+/i
        });

which is equivalent to:

これは次と等価だ:

    parser = new Parse::RecDescent (q{
        expression: and_expr '||' expression
                        { new expression_node (@item[1..3]) }
                  | and_expr
        and_expr:   not_expr '&&' and_expr
                        { new and_expr_node (@item[1..3]) }
                |   not_expr
        not_expr:   '!' brack_expr
                        { new not_expr_node (@item[1..2]) }
                |   brack_expr
        brack_expr: '(' expression ')'
                        { new brack_expr_node (@item[1..3]) }
                  | identifier
        identifier: /[a-z]+/i
                        { new identifer_node (@item[1]) }
        });

Note that, if a production already ends in an action, no autoaction is appended to it. For example, in this version:

注意として、既にプロダクションの終わりがアクションである場合、 オートアクションは追加されない。例えば:

    $::RD_AUTOACTION = q
      { $#item==1 ? $item[1] : new ${"$item[0]_node"} (@item[1..$#item]) };
    parser = new Parse::RecDescent (q{
        expression: and_expr '&&' expression | and_expr
        and_expr:   not_expr '&&' and_expr   | not_expr
        not_expr:   '!' brack_expr           | brack_expr
        brack_expr: '(' expression ')'       | identifier
        identifier: /[a-z]+/i
                        { new terminal_node($item[1]) }
        });

each identifier match produces a terminal_node object, not an identifier_node object.

identifierに対するマッチはそれぞれterminal_nodeオブジェクトを 生成するのであって、identifier_nodeオブジェクトではない

A level 1 warning is issued each time an "autoaction" is added to some production.

アートアクションがプロダクションに追加されるときに、レベル1の警告が 発生する。

オートツリー (Autotrees)

A commonly needed autoaction is one that builds a parse-tree. It is moderately tricky to set up such an action (which must treat terminals differently from non-terminals), so Parse::RecDescent simplifies the process by providing the <autotree> directive.

一般に、オートアクションが必要となるのは解析木を構築する時である。 そのようなアクション(終端記号と非終端記号を分けて扱わなければならない) を用意するには少々手の込んだ手法が入り用だ。そこで、Parse::RecDescentは、 <autotree>ディレクティブによって、このプロセスを簡単にしている。

If this directive appears at the start of grammar, it causes Parse::RecDescent to insert autoactions at the end of any rule except those which already end in an action. The action inserted depends on whether the production is an intermediate rule (two or more items), or a terminal of the grammar (i.e. a single pattern or string item).

このディレクティブが文法の開始時に現れると、Parse::RecDescentは、既に アクションで終わるようになっているものを除いて、規則の最後に オートアクションを挿入する。挿入されるアクションは、そのプロダクションが 中間規則(2つ以上のアイテム)か、文法の終端記号(パターン、なしいは文字列 による単一アイテム)かによって変わる。

So, for example, the following grammar:

よって、例えば次のような文法では:

        <autotree>
        file    : command(s)
        command : get | set | vet
        get     : 'get' ident ';'
        set     : 'set' ident 'to' value ';'
        vet     : 'check' ident 'is' value ';'
        ident   : /\w+/
        value   : /\d+/

is equivalent to:

以下と等価になる:

        file    : command(s)                    { bless \%item, $item[0] }
        command : get                           { bless \%item, $item[0] }
                | set                           { bless \%item, $item[0] }
                | vet                           { bless \%item, $item[0] }
        get     : 'get' ident ';'               { bless \%item, $item[0] }
        set     : 'set' ident 'to' value ';'    { bless \%item, $item[0] }
        vet     : 'check' ident 'is' value ';'  { bless \%item, $item[0] }
        ident   : /\w+/          { bless {__VALUE__=>$item[1]}, $item[0] }
        value   : /\d+/          { bless {__VALUE__=>$item[1]}, $item[0] }

Note that each node in the tree is blessed into a class of the same name as the rule itself. This makes it easy to build object-oriented processors for the parse-trees that the grammar produces. Note too that the last two rules produce special objects with the single attribute '__VALUE__'. This is because they consist solely of a single terminal.

ツリー内の各ノードは、規則自身と同じ名前のクラスにblessされている ことに注意。これによって簡単に、文法が生み出した構文解析木用の オブジェクト指向なプロセッサが構築できる。また、後二つの規則は 一つの属性'__VALUE__'を持った特殊なオブジェクトを生成することにも 注意。これは、それらが単一の終端記号で構成されているためである。

This autoaction-ed grammar would then produce a parse tree in a data structure like this:

このオートアクションを指定された文法は、以下のようなデータ構造の 構文解析木を生成する:

        {
          file => {
                    command => {
                                 [ get => {
                                            identifier => { __VALUE__ => 'a' },
                                          },
                                   set => {
                                            identifier => { __VALUE__ => 'b' },
                                            value      => { __VALUE__ => '7' },
                                          },
                                   vet => {
                                            identifier => { __VALUE__ => 'b' },
                                            value      => { __VALUE__ => '7' },
                                          },
                                  ],
                               },
                  }
        }

(except, of course, that each nested hash would also be blessed into the appropriate class).

(もちろん、ネストされたハッシュがそれぞれ、適切なクラスにblessされても いることは除く。)

オートスタブ (Autostubbing)

Normally, if a subrule appears in some production, but no rule of that name is ever defined in the grammar, the production which refers to the non-existent subrule fails immediately. This typically occurs as a result of misspellings, and is a sufficiently common occurance that a warning is generated for such situations.

通常、あるプロダクション内でサブ規則が現れた場合(ただし、文法内で その名前が定義されているものを除く)、存在しないサブ規則を参照する プロダクションは直ちに照合に失敗する。これは典型的には、スペルミスで 発生する。そのような状況に対し警告が発生するのは、ごく一般的な ことである。

However, when prototyping a grammar it is sometimes useful to be able to use subrules before a proper specification of them is really possible. For example, a grammar might include a section like:

しかしながら、文法をプロトタイプする際、サブ規則を適切に宣言する前に 利用することができれば便利なことがある。そしてこれは実際可能である。 例えば、次のようなセクションを含んだ文法において:

        function_call: identifier '(' arg(s?) ')'
        identifier: /[a-z]\w*/i

where the possible format of an argument is sufficiently complex that it is not worth specifying in full until the general function call syntax has been debugged. In this situation it is convenient to leave the real rule arg undefined and just slip in a placeholder (or "stub"):

このような場合、引数のとり得るフォーマットは非常に複雑なため、一般的な 関数コールシンタックスがデバッグされてしまわない限り、仕様を完全に 記述するのは無意味である。こういう状況では、本当の規則argは未定義の ままにしておいて、単にプレースホルダー(スタブ (stub) )に入れておく のが便利だ。

        arg: 'arg'

so that the function call syntax can be tested with dummy input such as:

そうしておいて、ダミー入力を使って関数コールシンタックスをテストする:

        f0()
        f1(arg)
        f2(arg arg)
        f3(arg arg arg)

et cetera.

等々。

Early in prototyping, many such "stubs" may be required, so Parse::RecDescent provides a means of automating their definition. If the variable $::RD_AUTOSTUB is defined when a parser is built, a subrule reference to any non-existent rule (say, sr), causes a "stub" rule of the form:

プロトタイプの初期では、このようなスタブが大量に必要となる。そこで Parse::RecDescentは、それらの定義を自動化する手段を提供している。 パーサが構築される際、変数$::RD_AUTOSTUBが定義されていれば、 存在しない規則(例としてsr)を参照するサブ規則は、次のような 形式のスタブ規則を発生させる:

        sr: 'sr'

to be automatically defined in the generated parser. A level 1 warning is issued for each such "autostubbed" rule.

これは生成されたパーサにおいて自動的に定義される。このような オートスタブされた規則ができる度に、レベル1警告が発生する。

Hence, with $::AUTOSTUB defined, it is possible to only partially specify a grammar, and then "fake" matches of the unspecified (sub)rules by just typing in their name.

$::AUTOSTUBを定義することによって、部分的に文法を定義することが 可能になり、名前をタイプするだけで未指定の(サブ)規則を擬似的に 照合することが可能になる。

先読み (Look-ahead)

If a subrule, token, or action is prefixed by "...", then it is treated as a "look-ahead" request. That means that the current production can (as usual) only succeed if the specified item is matched, but that the matching does not consume any of the text being parsed. This is very similar to the /(?=...)/ look-ahead construct in Perl patterns. Thus, the rule:

サブ規則、トークン、あるいはアクションの前に"..."が置かれた場合、これは "先読み要求"(look-ahead)として扱われる。どういうことかというと、現在の プロダクションは(通常)、指定されたアイテムがマッチした場合にのみ成功するが、 この照合の場合、パースされるテキストが消費されない。これはPerlの 正規表現パターンの先読み構造/(?=...)/とよく似ている。よって、規則:

        inner_word: word ...word

will match whatever the subrule "word" matches, provided that match is followed by some more text which subrule "word" would also match (although this second substring is not actually consumed by "inner_word")

は、サブ規則"word"にマッチするものは何でもマッチする。このとき、 このマッチに続いてサブ規則"word"にマッチするさらなるテキストが続く(ただし、 この二番目の文字列は実際には"inner_word"によって消費されない)。

Likewise, a "...!" prefix, causes the following item to succeed (without consuming any text) if and only if it would normally fail. Hence, a rule such as:

同様に、"...!" 前置子は、続くアイテムがマッチに失敗したときだけ、 (テキストの消費無しに)マッチに成功したことになる。それゆえ、 次のような規則:

        identifier: ...!keyword ...!'_' /[A-Za-z_]\w*/

matches a string of characters which satisfies the pattern /[A-Za-z_]\w*/, but only if the same sequence of characters would not match either subrule "keyword" or the literal token '_'.

は、正規表現パターン/[A-Za-z_]\w*/を満たすキャラクタ文字列にマッチ する。しかしこれは、その同じキャラクタの連なりが、サブ規則"keyword"か リテラルトークン'_'のいずれかにマッチしない場合に限る。

Sequences of look-ahead prefixes accumulate, multiplying their positive and/or negative senses. Hence:

先読み前置子を繋げていくと、その肯定・否定の意味が掛け合わされていく。 よって:

        inner_word: word ...!......!word

is exactly equivalent the the original example above (a warning is issued in cases like these, since they often indicate something left out, or misunderstood).

これは、先にあげた最初の例と正確に等しい(このようなケースでは警告が 発生する。というのも、これらはしばしば、[先読み前置子を]忘れていたり、 間違った理解をしている兆候といえるからである)。

Note that actions can also be treated as look-aheads. In such cases, the state of the parser text (in the local variable $text) after the look-ahead action is guaranteed to be identical to its state before the action, regardless of how it's changed within the action (unless you actually undefine $text, in which case you get the disaster you deserve :-).

アクションもまた、先読みとして扱われうることに注意。そのような場合、 先読みアクションの後ろのテキストの状態(ローカル変数$text)は、 そのアクションの前の状態と全く同じであることが保証される。これは そのアクション内でいかに状態が変化しようとも関係ない($textを 本当にundefしない限りは。って、そんなことをしたら、あなたに災いが 降りかかるだろうが(笑))。

ディレクティブ (Directives)

Directives are special pre-defined actions which may be used to alter the behaviour of the parser. There are currently eighteen directives:

ディレクティブ(directive)とは、パーサの振る舞いを変更するために利用する 予約された特別なアクションである。現在、18のディレクティブがある:

<commit>, <uncommit>, <reject>, <score>, <autoscore>, <skip>, <resync>, <error>, <rulevar>, <matchrule>, <leftop>, <rightop>, <defer>, <nocheck>, <perl_quotelike>, <perl_codeblock>, <perl_variable>, そして <token>.

サブ規則の引数リスト (Subrule argument lists)

It is occasionally useful to pass data to a subrule which is being invoked. For example, consider the following grammar fragment:

呼び出されるサブ規則にデータを渡すことができると便利なことがある。例えば、 次のような文法の一部を考えてみると:

        classdecl: keyword decl
        keyword:   'struct' | 'class';
        decl:      # WHATEVER

The decl rule might wish to know which of the two keywords was used (since it may affect some aspect of the way the subsequent declaration is interpreted). Parse::RecDescent allows the grammar designer to pass data into a rule, by placing that data in an argument list (that is, in square brackets) immediately after any subrule item in a production. Hence, we could pass the keyword to decl as follows:

decl規則は、二つのkeywordのどちらが使われているのかを知りたい (続く宣言の解釈方法に影響を与えるから)。Parse::RecDescentは、 文法の設計者がデータを規則に渡すことができるようにしている。これは プロダクションの任意のサブ規則アイテムの直後に、そのデータを 引数リスト(ブラケット内)の中に置くことによってなされる。 それゆえ、declにkeywordを渡すには:

        classdecl: keyword decl[ $item[1] ]
        keyword:   'struct' | 'class';
        decl:      # WHATEVER

The argument list can consist of any number (including zero!) of comma-separated Perl expressions. In other words, it looks exactly like a Perl anonymous array reference. For example, we could pass the keyword, the name of the surrounding rule, and the literal 'keyword' to decl like so:

引数リストは、任意の数(0も含む!)のカンマで区切られたPerlの式を含む ことができる。つまり、Perlの無名配列リファレンスにそっくりなのである。 例えば次のようにkeyword、取り囲んでいる規則、そして文字列の'keyword'を declに渡すことができる:

        classdecl: keyword decl[$item[1],$item[0],'keyword']
        keyword:   'struct' | 'class';
        decl:      # WHATEVER

Within the rule to which the data is passed (decl in the above examples) that data is available as the elements of a local variable @arg. Hence decl might report its intentions as follows:

データが渡された規則(上の例ではdecl)内では、そのデータは局所変数 @argの要素として利用することができる。よってdeclはその性向を 次のようにして報告できる:

        classdecl: keyword decl[$item[1],$item[0],'keyword']
        keyword:   'struct' | 'class';
        decl:      { print "Declaring $arg[0] (a $arg[2])\n";
                     print "(this rule called by $arg[1])" }

Subrule argument lists can also be interpreted as hashes, simply by using the local variable %arg instead of @arg. Hence we could rewrite the previous example:

サブ規則の引数リストはハッシュとしても解釈できる。これは単に@argの 代わりに局所変数%argを利用すればよい。よって前の例は次のように書き直せる:

        classdecl: keyword decl[keyword => $item[1],
                                caller  => $item[0],
                                type    => 'keyword']
        keyword:   'struct' | 'class';
        decl:      { print "Declaring $arg{keyword} (a $arg{type})\n";
                     print "(this rule called by $arg{caller})" }

Both @arg and %arg are always available, so the grammar designer may choose whichever convention (or combination of conventions) suits best.

@arg%argはどちらもいつでも利用できる。だから文法の設計者は 利便に最も適した方を選べばよい。

Subrule argument lists are also useful for creating "rule templates" (especially when used in conjunction with the <matchrule:...> directive). For example, the subrule:

サブ規則の引数リストは"規則テンプレート"を作成するのにも利用できる (特に<matchrule:...>ディレクティブと一緒に使う場合)。 例えば、次のサブ規則:

        list:     <matchrule:$arg{rule}> /$arg{sep}/ list[%arg]
                        { $return = [ $item[1], @{$item[3]} ] }
            |     <matchrule:$arg{rule}>
                        { $return = [ $item[1]] }

is a handy template for the common problem of matching a separated list. For example:

は、区切られたリストにマッチする場合に共通する問題に対する便利な テンプレートになる。例えば:

        function: 'func' name '(' list[rule=>'param',sep=>';'] ')'
        param:    list[rule=>'name',sep=>','] ':' typename
        name:     /\w+/
        typename: name

When a subrule argument list is used with a repeated subrule, the argument list goes before the repetition specifier:

サブ規則の引数リストが反復サブ規則と一緒に使われるとき、引数リストは 反復指定子の前に来る:

        list:   /some|many/ thing[ $item[1] ](s)

The argument list is "late bound". That is, it is re-evaluated for every repetition of the repeated subrule. This means that each repeated attempt to match the subrule may be passed a completely different set of arguments if the value of the expression in the argument list changes between attempts. So, for example, the grammar:

引数リストは"遅延バインディング"である。そのため、反復サブ規則の 全ての繰り返しで再評価される。このことは、サブ規則の照合が試みられる 度に、引数の式の値が異なれば完全に異なった引数のセットが渡される ことを意味する。よって次の文法の例では:

        { $::species = 'dogs' }
        pair:   'two' animal[$::species](s)
        animal: /$arg[0]/ { $::species = 'cats' }

will match the string "two dogs cats cats" completely, whereas it will only match the string "two dogs dogs dogs" up to the eighth letter. If the value of the argument list were "early bound" (that is, evaluated only the first time a repeated subrule match is attempted), one would expect the matching behaviours to be reversed.

文字列"two dogs cats cats"は完全にマッチする。これに対し、文字列 "two dogs dogs dogs"は8文字目までしかマッチしない。もしも引数リスト の値が"事前バインディング"だったなら(すなわち、反復サブ規則のマッチ が試みられる一番最初だけ評価されるなら)、照合の振る舞いは逆になる のが期待できたであろうに。

Of course, it is possible to effectively "early bind" such argument lists by passing them a value which does not change on each repetition. For example:

もちろん、反復の度に変化しない値を渡すことによって、そのような引数リストを 効果的に"事前バインディング"することが可能である。例:

        { $::species = 'dogs' }
        pair:   'two' { $::species } animal[$item[2]](s)
        animal: /$arg[0]/ { $::species = 'cats' }

Arguments can also be passed to the start rule, simply by appending them to the argument list with which the start rule is called (after the "line number" parameter). For example, given:

単純に("行番号"パラメータの後で)開始規則が呼び出されるときに 使う引数リストに引数を加えることによって、開始規則に渡すこともできる。 次のような例の場合:

        $parser = new Parse::RecDescent ( $grammar );
        $parser->data($text, 1, "str", 2, \@arr);
        #             ^^^^^  ^  ^^^^^^^^^^^^^^^
        #               |    |         |
        #     解析用テキスト |         |
        #     スタート時の行番号       |
        #     規則 data に渡される@argの要素データ
        #             ^^^^^  ^  ^^^^^^^^^^^^^^^
        #               |    |         |
        # TEXT TO BE PARSED  |         |
        # STARTING LINE NUMBER         |
        # ELEMENTS OF @arg WHICH IS PASSED TO RULE data

then within the productions of the rule data, the array @arg will contain ("str", 2, \@arr).

こうすると規則dataのプロダクション内で、配列@arg("str", 2, \@arr) を含むことになる。

オルタネーション (Alternations)

Alternations are implicit (unnamed) rules defined as part of a production. An alternation is defined as a series of '|'-separated productions inside a pair of round brackets. For example:

オルタネーションとは、プロダクションの一部として定義される暗黙の (名前のない)規則である。オルタネーションは丸括弧の中の'|'で区切られた 一連のプロダクションとして定義される。例えば:

        character: 'the' ( good | bad | ugly ) /dude/

Every alternation implicitly defines a new subrule, whose automatically-generated name indicates its origin: "_alternation_<I>_of_production_<P>_of_rule<R>" for the appropriate values of <I>, <P>, and <R>. A call to this implicit subrule is then inserted in place of the brackets. Hence the above example is merely a convenient short-hand for:

全てのオルタネーションは暗黙の内に新しいサブ規則を定義する。それらが 有する自動生成された名前はその出自を示している: "_alternation_<I>_of_production_<P>_of_rule<R>"は、<I>、<P>、そして<R> に相応しい値となる。この暗黙のサブ規則に対する呼び出しは、括弧の位置に 挿入される。それゆえ、上の例は単に以下に対する簡便な省略記法となる:

        character: 'the'
                   _alternation_1_of_production_1_of_rule_character
                   /dude/
        _alternation_1_of_production_1_of_rule_character:
                   good | bad | ugly

Since alternations are parsed by recursively calling the parser generator, any type(s) of item can appear in an alternation. For example:

オルタネーションは再帰的にパーサジェネレータを呼び出して解析されるので、 どんなタイプのアイテムもオルタネーションの中に現れうる。例えば:

        character: 'the' ( 'high' "plains"      # Silent, with poncho
                         | /no[- ]name/         # Silent, no poncho
                         | vengeance_seeking    # Poncho-optional
                         | <error>
                         ) drifter

In this case, if an error occurred, the automatically generated message would be:

この場合、エラーが生じると自動生成されるメッセージは:

        ERROR (line <N>): Invalid implicit subrule: Expected
                          'high' or /no[- ]name/ or generic,
                          but found "pacifist" instead

Since every alternation actually has a name, it's even possible to extend or replace them:

全てのオルタネーションは実際には名前を持つので、それらを拡張したり 置換したりすることができる:

        parser->Replace(
                "_alternation_1_of_production_1_of_rule_character:
                        'generic Eastwood'"
                        );

More importantly, since alternations are a form of subrule, they can be given repetition specifiers:

さらに重要なことに、オルタネーションはサブ規則の一形式なので、反復指定子を 与えることができる:

        character: 'the' ( good | bad | ugly )(?) /dude/

増加解析 (Incremental Parsing)

Parse::RecDescent provides two methods - Extend and Replace - which can be used to alter the grammar matched by a parser. Both methods take the same argument as Parse::RecDescent::new, namely a grammar specification string

Parse::RecDescentは二つのメソッド - ExtendReplace - を提供 している。これらは、パーサが照合する文法に変更を加えるために用いられる。 どちらのメソッドもParse::RecDescent::newと同じ引数、すなわち、文法仕様の 文字列をとる。

Parse::RecDescent::Extend interprets the grammar specification and adds any productions it finds to the end of the rules for which they are specified. For example:

Parse::RecDescent::Extendは文法仕様を解釈し、見出されたプロダクションを 指定されている規則の最後に加える。例えば:

        $add = "name: 'Jimmy-Bob' | 'Bobby-Jim'\ndesc: colour /necks?/";
        parser->Extend($add);

adds two productions to the rule "name" (creating it if necessary) and one production to the rule "desc".

上の例では、規則"name"(必要があれば生成される)に対して二つの プロダクションと、規則"desc"に対して一つのプロダクションが付け加えられる。

Parse::RecDescent::Replace is identical, except that it first resets are rule specified in the additional grammar, removing any existing productions. Hence after:

Parse::RecDescent::Replaceも同様なのだが、既にあるプロダクションを削除する ことによって、追加文法で指定された規則が最初にリセットされる。 よって、使用後は:

        $add = "name: 'Jimmy-Bob' | 'Bobby-Jim'\ndesc: colour /necks?/";
        parser->Replace($add);

are are only valid "name"s and the one possible description.

上の例が唯一の正しい"name"で、一つの可能性のある説明になる。

A more interesting use of the Extend and Replace methods is to call them inside the action of an executing parser. For example:

ExtendReplaceメソッドのさらに面白い使い方は、実行中のパーサの アクション内でそれらを呼び出すことだ。例えば:

        typedef: 'typedef' type_name identifier ';'
                       { $thisparser->Extend("type_name: '$item[3]'") }
               | <error>
        identifier: ...!type_name /[A-Za-z_]w*/

which automatically prevents type names from being typedef'd, or:

これは自動的に型名(type name)がtypedefされるのを妨げる。あるいは:

        command: 'map' key_name 'to' abort_key
                       { $thisparser->Replace("abort_key: '$item[2]'") }
               | 'map' key_name 'to' key_name
                       { map_key($item[2],$item[4]) }
               | abort_key
                       { exit if confirm("abort?") }
        abort_key: 'q'
        key_name: ...!abort_key /[A-Za-z]/

which allows the user to change the abort key binding, but not to unbind it.

これでユーザは中断キーを変更することができる。ただしバインド解除はできない。

The careful use of such constructs makes it possible to reconfigure a a running parser, eliminating the need for semantic feedback by providing syntactic feedback instead. However, as currently implemented, Replace() and Extend() have to regenerate and re-eval the entire parser whenever they are called. This makes them quite slow for large grammars.

このような構築を気をつけて使えば、意味解析フィードバックの必要性を排除し、 代わりに構文上のフィードバックを提供することによって、実行中のパーサを 再構成することができる。しかし現在の実装では、Replace()Extend() は呼び出される度に、パーサを丸ごと再生成し、再度evalしなければ ならない。これは文法が巨大な場合、非常に遅くなってしまう。

In such cases, the judicious use of an interpolated regex is likely to be far more efficient:

そういう場合、展開される正規表現をうまく使うことによって、ずっと効率的な ものにすることができる:

        typedef: 'typedef' type_name/ identifier ';'
                       { $thisparser->{local}{type_name} .= "|$item[3]" }
               | <error>
        identifier: ...!type_name /[A-Za-z_]w*/
        type_name: /$thisparser->{local}{type_name}/

パーサのプリコンパイル (Precompiling parsers)

Normally Parse::RecDescent builds a parser from a grammar at run-time. That approach simplifies the design and implementation of parsing code, but has the disadvantage that it slows the parsing process down - you have to wait for Parse::RecDescent to build the parser every time the program runs. Long or complex grammars can be particularly slow to build, leading to unacceptable delays at start-up.

通常、Parse::RecDescentは、実行時に文法からパーサを構築する。この アプローチはパース用コードの設計と実装を単純化してくれる。しかし、 パース処理が遅くなるという不利を抱えることになる。プログラムを実行する 度に、あなたはParse::RecDescentがパーサを構築するのを待たなくてはならない。 長い、あるいは複雑な文法は殊のほか構築を遅らせ、開始までに我慢できない 遅れをもたらすだろう。

To overcome this, the module provides a way of "pre-building" a parser object and saving it in a separate module. That module can then be used to create clones of the original parser.

これを何とかするために、このモジュールは、パーサオブジェクトの"先行構築"と、 それを別モジュールに分離して保存する方法を提供している。そのモジュールを 使えば、オリジナルのパーサのクローンを生成することができる。

A grammar may be precompiled using the Precompile class method. For example, to precompile a grammar stored in the scalar $grammar, and produce a class named PreGrammar in a module file named PreGrammar.pm, you could use:

クラスメソッドPrecompileを使うと、文法がプリコンパイルされる。例えば、 スカラー変数$grammarに格納されている文法をプリコンパイルし、PreGrammar.pm というモジュールファイルにPreGrammarという名前のクラスを作成するには、 次のようにする:

        use Parse::RecDescent;
        Parse::RecDescent->Precompile($grammar, "PreGrammar");

The first argument is the grammar string, the second is the name of the class to be built. The name of the module file is generated automatically by appending ".pm" to the last element of the class name. Thus

最初の引数は文法の文字列、二番目は構築されるクラスの名前だ。 モジュールファイルの名前は、クラス名の最終要素に".pm"を加えて自動的に 生成される。それゆえ:

        Parse::RecDescent->Precompile($grammar, "My::New::Parser");

would produce a module file named Parser.pm.

これはParser.pmという名前のモジュールファイルができる。

It is somewhat tedious to have to write a small Perl program just to generate a precompiled grammar class, so Parse::RecDescent has some special magic that allows you to do the job directly from the command-line.

プリコンパイルされた文法用のクラスを生成するためだけに、小さな Perlプログラムを書かねばならないのは、なんとも退屈なことだ。そこで Parse::RecDescentは特別な魔法でもって、あなたがコマンドラインから ダイレクトにこの仕事を行なえるようにしてくれる。

If your grammar is specified in a file named grammar, you can generate a class named Yet::Another::Grammar like so:

grammarというファイルの中で文法が設定されているとして、あなたが Yet::Another::Grammarというクラスを生成するには:

        > perl -MParse::RecDescent - grammar Yet::Another::Grammar

This would produce a file named Grammar.pm containing the full definition of a class called Yet::Another::Grammar. Of course, to use that class, you would need to put the Grammar.pm file in a directory named Yet/Another, somewhere in your Perl include path.

これでクラス名Yet::Another::Grammarの完全な定義を含んだ Grammar.pmという名前のファイルが生成される。もちろん、このクラスを 使うには、Perlのインクルードパスが通ったYet/Anotherという名前の ディレクトリにGrammar.pmファイルを置かなければならない。

Having created the new class, it's very easy to use it to build a parser. You simply use the new module, and then call its new method to create a parser object. For example:

新しいクラスをつくってしまえば、パーサ構築のためにこれを利用する のはいともたやすい。新しいモジュールを単にuseし、パーサモジュール を生成するためにnewメソッドを呼び出すだけだ。例えば:

        use Yet::Another::Grammar;
        my $parser = Yet::Another::Grammar->new();

The effect of these two lines is exactly the same as:

上の二行の結果は次のものと全く同じだ:

        use Parse::RecDescent;
        open GRAMMAR_FILE, "grammar" or die;
        local $/;
        my $grammar = <GRAMMAR_FILE>;
        my $parser = Parse::RecDescent->new($grammar);

only considerably faster.

ただ、ずいぶん速いという点が違う。

Note however that the parsers produced by either approach are exactly the same, so whilst precompilation has an effect on set-up speed, it has no effect on parsing speed. RecDescent 2.0 will address that problem.

しかし注意して欲しい。いずれのアプローチで生成されたパーサも全く同じもの である。そしてプリコンパイルされた方がセットアップのスピードに影響を 与えるといえども、解析のスピードには影響がない。RecDescent 2.0 では この問題に取り組むつもりだ。

Parse::RecDescentのメタ文法 (A Metagrammar for Parse::RecDescent)

The following is a specification of grammar format accepted by Parse::RecDescent::new (specified in the Parse::RecDescent grammar format!):

以下は、Parse::RecDescent::newが受け付ける文法書式の仕様である (Parse::RecDescentの文法書式で設定されている!):

 grammar    : components(s)
 component  : rule | comment
 rule       : "\n" identifier ":" production(s?)
 production : items(s)
 item       : lookahead(?) simpleitem
            | directive
            | comment
 lookahead  : '...' | '...!'                   # 肯定あるいは否定の先読み
 simpleitem : subrule args(?)                  # 新たな規則にマッチ
            | repetition                       # 繰り返されるサブ規則にマッチ
            | terminal                         # 次の入力にマッチ
            | bracket args(?)                  # 選択アイテムにマッチ
            | action                           # 何か行なう
 subrule    : identifier                       # 規則名
 args       : {extract_codeblock($text,'[]')}  # 配列リファレンスと全く同じ
 repetition : subrule args(?) howoften
 howoften   : '(?)'                            # 0ないしは1回
            | '(s?)'                           # 0回以上
            | '(s)'                            # 1回以上
            | /(\d+)[.][.](/\d+)/              # $1 から $2 回
            | /[.][.](/\d*)/                   # 最大でも $1 回
            | /(\d*)[.][.])/                   # 少なくとも $1 回
 terminal   : /[/]([\][/]|[^/])*[/]/           # 展開される正規表現パターン
            | /"([\]"|[^"])*"/                 # 展開されるリテラル
            | /'([\]'|[^'])*'/                 # 展開されないリテラル
 action     : { extract_codeblock($text) }     # 埋め込みのPerlコード
 bracket    : '(' Item(s) production(s?) ')'   # 選択的なサブ規則
 directive  : '<commit>'                       # プロダクションにcommit
            | '<uncommit>'                     # commitのキャンセル
            | '<resync>'                       # 改行をスキップ
            | '<resync:' pattern '>'           # <pattern>をスキップ
            | '<reject>'                       # このプロダクションを失敗させる
            | '<reject:' condition '>'         # もし<condition>なら失敗
            | '<error>'                        # エラーの報告
            | '<error:' string '>'             # "<string>"としてエラーを報告
            | '<error?>'                       # commitされたときだけエラー
            | '<error?:' string '>'            #   "    "    "    "
            | '<rulevar:' /[^>]+/ '>'          # 規則内に局所化された変数を定義
            | '<matchrule:' string '>'         # stringという名の規則を呼び出す
 identifier : /[a-z]\w*/i                      # アルファベットから始める
 comment    : /#[^\n]*/                        # Perlと一緒
 pattern    : {extract_bracketed($text,'<')}   # allow embedded "<..>"
 condition  : {extract_codeblock($text,'{<')}  # 完全なPerlの式
 string     : {extract_variable($text)}        # 任意のPerl変数
            | {extract_quotelike($text)}       #   あるいはクォート風文字列
            | {extract_bracketed($text,'<')}   #   あるいはブラケットで囲まれている

おや? (GOTCHAS)

This section describes common mistakes that grammar writers seem to make on a regular basis.

このセクションでは、文法作成者が基礎的なところで犯しがちなよくある間違い について言及する。

1. 常にパースを失敗させるエラーの予測

A common mistake when using error messages is to write the grammar like this:

エラーメッセージを利用する際によくある間違いは、次のような文法を書いてしまうことだ:

        file: line(s)
        line: line_type_1
            | line_type_2
            | line_type_3
            | <error>

The expectation seems to be that any line that is not of type 1, 2 or 3 will invoke the <error> directive and thereby cause the parse to fail.

ここで期待しているのは、lineがタイプ1,2,3のいずれにも合致しなければ、 <error>ディレクティブを呼び出してパースを失敗させることであろう。

Unfortunately, that only happens if the error occurs in the very first line. The first rule states that a file is matched by one or more lines, so if even a single line succeeds, the first rule is completely satisfied and the parse as a whole succeeds. That means that any error messages generated by subsequent failures in the line rule are quietly ignored.

残念ながら、ちょうど一つ目のlineでエラーが現れたときにしかこれは起きない。 最初の規則は、fileが1つ以上のlineにマッチすると述べている。だから一つでも lineが成功すれば、一番目の規則は完全に要求が満たされ、パースは全体として 成功になる。つまり、その後で規則lineが失敗して生み出されたエラーメッセージ は完全に無視されることになる。

Typically what's really needed is this:

本当に必要だったことの典型例:

        file: line(s) eofile    { $return = $item[1] }
        line: line_type_1
            | line_type_2
            | line_type_3
            | <error>
        eofile: /^\Z/

The addition of the eofile subrule to the first production means that a file only matches a series of successful line matches that consume the complete input text. If any input text remains after the lines are matched, there must have been an error in the last line. In that case the eofile rule will fail, causing the entire file rule to fail too.

最初の規則にサブ規則eofileを加えることによって、入力テキストを完全に 消費する形で、lineが連続してマッチに成功した場合にのみ、fileはマッチ する。もしlineがマッチした後で入力テキストが何か残っているなら、最後の lineにエラーがあったに違いない。この場合、規則eofileは失敗し、 規則file全体も失敗となる。

Note too that eofile must match /^\Z/ (end-of-text), not /^\cZ/ or /^\cD/ (end-of-file).

eofile/^\Z/ (end-of-text) にマッチしなければならないのであって、 /^\cZ//^\cD/ (end-of-file) ではないことにも注意。

And don't forget the action at the end of the production. If you just write:

そして忘れてならないのが、プロダクションの最後にあるアクションだ。もし 単に次のように書いたなら:

        file: line(s) eofile

then the value returned by the file rule will be the value of its last item: eofile. Since eofile always returns an empty string on success, that will cause the file rule to return that empty string. Apart from returning the wrong value, returning an empty string will trip up code such as:

規則fileが返す値は、その最後のアイテム:eofileの値である。 eofileは成功すると常に空文字列を返すので、規則fileは空文字列を返す ことになる。この誤った値を返すのとは別に、空文字列が返ってくることによって 次のようなコードに問題が起きる:

        $parser->file($filetext) || die;

(since "" is false).

(なぜなら、""は偽になるから。)

Remember that Parse::RecDescent returns undef on failure, so the only safe test for failure is:

Parse::RecDescentは失敗したときにundefを返すということを覚えておいて 欲しい。だから失敗したかどうかの唯一安全なテストは以下のようになる:

        defined($parser->file($filetext)) || die;

診断 (DIAGNOSTICS)

Diagnostics are intended to be self-explanatory (particularly if you use -RD_HINT (under perl -s) or define $::RD_HINT inside the program).

診断は自己説明のためにある(特に(perl -sで)-RD_HINTを使っている場合、 あるいはプログラム内で$::RD_HINTを定義している場合)。

Parse::RecDescent currently diagnoses the following:

現在、Parse::RecDescentは以下の診断を報告する:

作者

Damian Conway (damian@conway.org)

バグやイライラ (BUGS AND IRRITATIONS)

There are undoubtedly serious bugs lurking somewhere in this much code :-) Bug reports and other feedback are most welcome.

間違いなくこの膨大なコードのどこかに重大なバグが潜んでいる(笑) バグレポートその他のフィードバックは大歓迎。

Ongoing annoyances include:

現在進行中の悩ましい問題には以下のものが含まれる:

進行中の問題と今後の方向性 (ON-GOING ISSUES AND FUTURE DIRECTIONS)

  1. Repetitions are "incorrigibly greedy" in that they will eat everything they can and won't backtrack if that behaviour causes a production to fail needlessly. So, for example:

    繰り返しは、可能な限り全てを飲み込むという点で、"どうしようもなく貪欲" である。そして、その振る舞いが不必要にプロダクションを失敗させるならば、 後戻りすることもできないだろう。だから、次の例が:

            rule: subrule(s) subrule

    will never succeed, because the repetition will eat all the subrules it finds, leaving none to match the second item. Such constructions are relatively rare (and Parse::RecDescent::new generates a warning whenever they occur) so this may not be a problem, especially since the insatiable behaviour can be overcome "manually" by writing:

    成功することは決してない。というのも、繰り返しは見つけたサブ規則を全て 食らうからであり、二番目のアイテムにマッチするようなものは何も残さないからだ。 このような構成は比較的まれである(それに、このようなことが起きると Parse::RecDescent::newは警告を発す)。だからこれは問題ではないかも しれない。特に、この貪欲な振る舞いは"手動で"書き直せば克服できるという点で:

            rule: penultimate_subrule(s) subrule
            penultimate_subrule: subrule ...subrule

    The issue is that this construction is exactly twice as expensive as the original, whereas backtracking would add only 1/N to the cost (for matching N repetitions of subrule). I would welcome feedback on the need for backtracking; particularly on cases where the lack of it makes parsing performance problematical.

    問題は、後戻りによってたかだか1/Nのコスト(subruleN回繰り返される のにマッチするから)が付け加えられるにも関わらず、この構成だと元の かっきり二倍のコストがかかるという点だ。後戻りの必要性に関するフィードバック を待ちたい;特に、これをやらない場合に、パースのパフォーマンスに問題が生じる ケースでは。

  2. Having opened that can of worms, it's also necessary to consider whether there is a need for non-greedy repetition specifiers. Again, it's possible (at some cost) to manually provide the required functionality:

    パンドラの箱が開かれたついでに、貪欲でない反復指定子が必要であるかないかに ついても考えなければならない。ここでも再び、(ある程度コストはかかるが) 必要とする機能は手動で提供できる:

            rule: nongreedy_subrule(s) othersubrule
            nongreedy_subrule: subrule ...!othersubrule

    Overall, the issue is whether the benefit of this extra functionality outweighs the drawbacks of further complicating the (currently minimalist) grammar specification syntax, and (worse) introducing more overhead into the generated parsers.

    全体的に、問題はこの追加的な機能がもたらす利益が、(現在最小限に押さえている) 文法仕様の構文をさらに繁雑にしてしまうことと、(より悪いことに)パーサ生成 にいっそうオーバーヘッドをかけてしまう欠点とを、上回るかどうかということだ。

  3. An <autocommit> directive would be nice. That is, it would be useful to be able to say:

    <autocommit>ディレクティブは良いものになるだろう。便利にも 次のような書き方ができることになる:

            command: <autocommit>
            command: 'find' name
                   | 'find' address
                   | 'do' command 'at' time 'if' condition
                   | 'do' command 'at' time
                   | 'do' command
                   | unusual_command

    and have the generator work out that this should be "pruned" thus:

    そうするとジェネレータはこれを"刈り込んで"くれる。すなわち:

            command: 'find' name
                   | 'find' <commit> address
                   | 'do' <commit> command <uncommit>
                            'at' time
                            'if' <commit> condition
                   | 'do' <commit> command <uncommit>
                            'at' <commit> time
                   | 'do' <commit> command
                   | unusual_command

    There are several issues here. Firstly, should the <autocommit> automatically install an <uncommit> at the start of the last production (on the grounds that the "command" rule doesn't know whether an "unusual_command" might start with "find" or "do") or should the "unusual_command" subgraph be analysed (to see if it might be viable after a "find" or "do")?

    いくつかの問題がある。まず、<autocommit>は自動的に(規則 "command"は"unusual_command"が"find"か"do"ではじまるべきかどうかを知る ことはできないので)最後のプロダクションの始めに<uncommit>を 導入するべきだろうか?あるいは、"unusual_command"の部分グラフが ("find"か"do"の後でそれが見出せるかどうか)解析されるべきだろうか?

    The second issue is how regular expressions should be treated. The simplest approach would be simply to uncommit before them (on the grounds that they might match). Better efficiency would be obtained by analyzing all preceding literal tokens to determine whether the pattern would match them.

    二番目の問題は、正規表現をどう扱うかという点だ。最も単純なアプローチは、 正規表現の前で単にuncommitすることだ(それらはマッチするはずだから)。 より効率的なアプローチは、パターンがマッチするかどうかを決定するために、 先行するリテラルトークンを全て解析することよって得られる。

    Overall, the issues are: can such automated "pruning" approach a hand-tuned version sufficiently closely to warrant the extra set-up expense, and (more importantly) is the problem important enough to even warrant the non-trivial effort of building an automated solution?

    全体的に、問題は:このような自動化された"刈り込み"が、セットアップのための 余分な費用を保証するほど十分な手動チューニングによるアプローチたりうるのか どうかという点である。そして(さらに重要なことに)、この問題は、自動化され る解決方法を構築するための結構な努力を正当化するほど重要なのだろうか?

著作権

Copyright (c) 1997-2000, Damian Conway. All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the terms of the Perl Artistic License (see http://www.perl.com/perl/misc/Artistic.html)