ドキュメント
インストール
Node.js
pegjsコマンドを使うには、PEG.jsをグローバルにインストールしてください。:
$ npm install -g pegjs
JavaScript APIを使用するには、PEG.jsをローカルにインストールしてください。:
$ npm install pegjs
pegjsコマンドとJavaScript APIの両方が必要な場合は、PEG.jsを両方インストールしてください。
ブラウザ
PEG.jsライブラリ(通常版または最小化版)をダウンロードするか、Bowerを使ってインストールします。:
$ bower install pegjs
パーサーの生成
PEG.jsは、期待される入力を記述した文法からパーサーを生成し、パーサーが返すものを指定することができます(入力のマッチした部分に対してセマンティックアクションを使用します)。生成されたパーサー自体は、シンプルなAPIを持つJavaScriptオブジェクトです。
コマンドライン
文法からパーサーを生成するには、pegjsコマンドを使います。:
$ pegjs arithmetics.pegjs
これは、文法ファイルと同じ名前で拡張子が".js "のファイルにパーサーのソースコードを書き込みます。出力ファイルを明示的に指定することもできます:
$ pegjs -o arithmetics-parser.js arithmetics.pegjs
入力ファイルと出力ファイルの両方を省略した場合は、標準入力と標準出力が使用される。
デフォルトでは、生成されるパーサーはNode.jsモジュール・フォーマットです。これは--formatオプションで上書きできる。
いくつかのオプションで、生成されるパーサーを微調整できる:
--allowed-start-rules
:
パーサーが解析を開始するルールのカンマ区切りリスト(デフォルト:文法の最初のルール)。
--cache
:
パーサが結果をキャッシュするようになり、病的なケースでの指数関数的な構文解析時間を避けることができるが、パーサは遅くなる。
--dependency
:
指定された依存関係をパーサに要求させる(複数回指定可能)。
--export-var
:
モジュールローダーが検出されなかった場合に、パーサーオブジェクトが代入されるグローバル変数の名前。
--extra-options
peg.generateに渡す追加オプション(JSON形式)。
--extra-options-file
peg.generateに渡す追加オプション(JSON形式)のファイル。
--format
生成されるパーサーのフォーマット:amd、commonjs、globals、umd(デフォルト:commonjs)。
--optimize
生成されたパーサーを解析速度(speed)とコードサイズ(size)のどちらに最適化するかを選択する(デフォルト:speed)
--plugin
PEG.js に指定したプラグインを使わせます(複数指定可)。
--trace
パーサーに進捗をトレースさせる。
JavaScript API
Node.jsでは、PEG.jsパーサー・ジェネレーター・モジュールをrequireします:
var peg = require("pegjs");
ブラウザで、<script>
タグを使って、PEG.js ライブラリをウェブページやアプリケーションにインクルードします。PEG.jsがAMDローダーを検出すれば、それ自身をモジュールとして定義し、そうでなければ、APIはpegグローバルオブジェクトで利用可能になります。
パーサーを生成するには、peg.generateメソッドを呼び出し、パラメータとして文法を渡します:
var parser = peg.generate("start = ('a' / 'b')+");
このメソッドは、生成されたパーサーオブジェクトかそのソースコードを文字列として返します(出力オプションの値に依存します - 下記を参照)。文法が無効な場合は例外をスローします。例外には、エラーの詳細を示すメッセージ・プロパティが含まれます。
peg.generateにオプションオブジェクトを2番目のパラメータとして渡すことで、生成されるパーサーを微調整することができます。以下のオプションがサポートされています:
allowedStartRules
:
パーサーが解析を開始できるルール(デフォルト:文法の最初のルール)。
cache
:
trueの場合、パーサが結果をキャッシュするようになり、病的なケースでの指数関数的なパーシング時間を避けることができますが、パーサは遅くなります(デフォルト:false)。
dependencies
:
パーサーの依存関係、値はパーサーの依存関係にアクセスするために使用される変数を、それらをロードするために使用されるモジュールIDにマップするオブジェクトです。formatが "amd"、"commonjs"、または "umd "に設定されているときのみ有効です(デフォルト:{})。
exportVar
:
formatが "globals "または "umd "に設定されているときのみ有効(デフォルト:null)。
format
:
生成されるパーサーのフォーマット("amd"、"bare"、"commonjs"、"globals"、または "umd"); 出力が "source "に設定されているときのみ有効(デフォルトは "bare")。
optimize
:
生成されたパーサーを解析速度("speed")とコードサイズ("size")のどちらに最適化するかを選択します(デフォルトは "speed")。
output
:
parser "に設定すると、このメソッドは生成されたパーサー・オブジェクトを返します。"source "に設定すると、パーサー・ソース・コードを文字列として返します(デフォルトは "parser")。
plugins
:
使用するプラグイン
trace
:
パーサが進行状況をトレースするようにします(デフォルト:false)。
パーサーを使う
生成されたパーサーの使い方は簡単で、parseメソッドを呼び出し、パラメータとして入力文字列を渡すだけです。このメソッドはパース結果を返すか(正確な値はパーサーの生成に使われた文法に依存します)、入力が無効な場合は例外をスローします。例外には、エラーの詳細を示す location、expected、found、message プロパティが含まれます。
parser.parse("abba"); // returns ["a", "b", "b", "a"]
parser.parse("abcd"); // throws an exception
パーサーの動作を微調整するには、オプション・オブジェクトを2番目のパラメーターとしてparseメソッドに渡します。以下のオプションがサポートされています:
startRule
:
解析を開始するルールの名前。
tracer
:
使用するトレーサー。
パーサーは、独自のカスタム・オプションをサポートすることもできる。
文法 構文論と意味論
文法構文はJavaScriptに似ているが、行指向ではなく、トークン間の空白は無視される。JavaScriptスタイルのコメント(// ... や /* ... */)も使えます。
2*(3+4)のような単純な算術式を認識する文法の例を見てみよう。この文法から生成されたパーサーは、それらの値を計算する。
start
= additive
additive
= left:multiplicative "+" right:additive { return left + right; }
/ multiplicative
multiplicative
= left:primary "*" right:multiplicative { return left * right; }
/ primary
primary
= integer
/ "(" additive:additive ")" { return additive; }
integer "integer"
= digits:[0-9]+ { return parseInt(digits.join(""), 10); }
トップレベルでは、文法はルールで構成される(この例では5つある)。各ルールには、ルールを識別する名前(integerなど)と、入力テキストとマッチするパターンを定義する構文解析式(digits:[0-9]+ { return parseInt(digits.join(""), 10); }
など)があります。ルールには、エラーメッセージで使用する人間が読める名前を含めることもできます (この例では、整数ルールだけが人間が読める名前になっています)。構文解析は最初のルールから始まります。
ルール名はJavaScriptの識別子でなければならない。その後に等号("=")と構文解析式が続く。ルールに人間が読める名前がある場合は、名前と等号の間にJavaScriptの文字列として記述する。ルールは空白のみで区切る必要がある(その先頭は容易に認識できる)が、構文解析式の後にセミコロン(";")を置くことは可能である。
最初のルールの前には、イニシャライザ(中かっこ("{"と"}")で囲まれたJavaScriptコードの一部)を置くことができる。このコードは、生成されたパーサーがパージングを開始する前に実行されます。イニシャライザで定義されたすべての変数と関数は、ルールアクションと意味述語でアクセス可能です。イニシャライザ内のコードは、options変数を使用してパーサーに渡されたオプションにアクセスできます。イニシャライザ・コード内の中括弧は、バランスがとれていなければなりません。簡単なイニシャライザを使った文法の例を見てみましょう。
{
function makeInteger(o) {
return parseInt(o.join(""), 10);
}
}
start
= additive
additive
= left:multiplicative "+" right:additive { return left + right; }
/ multiplicative
multiplicative
= left:primary "*" right:multiplicative { return left * right; }
/ primary
primary
= integer
/ "(" additive:additive ")" { return additive; }
integer "integer"
= digits:[0-9]+ { return makeInteger(digits); }
ルールの構文解析式は、入力テキストを文法にマッチさせるために使われる。文字や文字クラスのマッチング、省略可能な部分や繰り返しの指示など、さまざまな種類の表現がある。式は他のルールへの参照を含むこともできる。以下の詳細な説明を参照のこと。
生成されたパーサーを実行するとき、式がテキストの一部分にうまくマッチすると、JavaScriptの値であるマッチ結果が生成されます。例えば
- リテラル文字列にマッチする式は、マッチしたテキストを含むJavaScript文字列を生成します。
- 繰り返し出現する部分式にマッチする式は、すべてのマッチを含む JavaScript 配列を生成します。
ルール名が式で使用されると、マッチ結果は開始ルールまでルールに伝搬します。生成されたパーサーは、解析に成功すると開始ルールのマッチ結果を返します。
中括弧("{"と"}")の中にあるJavaScriptコードで、先行するいくつかの式のマッチ結果を受け取り、JavaScript値を返します。この値は、直前の式のマッチ結果とみなされます(言い換えると、パーサー・アクションはマッチ結果トランスフォーマーです)。
算術の例では、多くのパーサー・アクションがある。digits:[0-9]+ { return parseInt(digits.join(""), 10); }
という式のアクションを考えてみましょう。digits:[0-9]+
という式のマッチ結果をパラメータとして受け取ります。これは、数字を結合して数値を形成し、JavaScriptの数値オブジェクトに変換します。
式タイプの解析
構文解析式にはいくつかの種類があり、中には部分式を含んで再帰的な構造を形成するものもある:
"literal"
:
'literal'
:
正確なリテラル文字列にマッチし、それを返す。文字列の構文はJavaScriptと同じ。リテラルの直後に i を付けると、大文字小文字を区別せずにマッチします。
.
:
正確に1文字にマッチし、文字列として返す。
[characters]
:
集合から1文字をマッチさせ、文字列として返す。リストの文字はJavaScriptの文字列と全く同じ方法でエスケープすることができます。文字のリストは範囲を含むこともできる(例えば [a-z]
は "全ての小文字 "を意味する)。文字の前に ^ を付けると、マッチする文字が反転します (例えば [^a-z]
は「小文字以外の全ての文字」を意味します)。リテラルの直後にiを付けると、大文字小文字を区別しないマッチになる。
rule
:
ルールの構文解析式に再帰的にマッチし、そのマッチ結果を返す。
( expression )
:
部分式にマッチし、そのマッチ結果を返します。
expression *
:
式の0回以上の繰り返しにマッチし、そのマッチ結果を配列で返します。マッチングは貪欲に行われます。つまり、パーサーは可能な限り多くの回数の式にマッチしようとします。正規表現とは異なり、バックトラックはありません。
expression +
:
式の1つ以上の繰り返しにマッチし、そのマッチ結果を配列で返します。マッチングは貪欲に行われます。つまり、パーサーは可能な限り多くの回数の式にマッチしようとします。正規表現とは異なり、バックトラックはありません。
expression ?
:
式のマッチを試みる。マッチに成功すればその結果を返し、そうでなければnullを返す。正規表現とは異なり、バックトラックはありません。
& expression
:
式のマッチを試みる。マッチに成功した場合はundefinedを返し、入力を消費しません。
! expression
:
Try to match the expression. If the match does not succeed, just return undefined and do not consume any input, otherwise consider the match failed.
& { predicate }
:
述語はJavaScriptコードの一部で、あたかも関数の中にあるかのように実行される。これは、直前の式でラベル付けされた式のマッチ結果を引数として取得します。return文を使って、JavaScriptの値を返す必要があります。返された値が真偽値で評価される場合、undefinedを返し、入力を消費しません。
述語の中のコードは、文法の最初にあるイニシャライザーで定義されたすべての変数と関数にアクセスできる。
述語の中のコードは、location関数を使って位置情報にアクセスすることもできます。これは次のようなオブジェクトを返します:
{
start: { offset: 23, line: 5, column: 6 },
end: { offset: 23, line: 5, column: 6 }
}
start プロパティと end プロパティはともに現在の解析位置を指す。offsetプロパティはゼロベースのインデックスとしてオフセットを含み、lineプロパティとcolumnプロパティは1ベースのインデックスとして行と列を含む。
述語内部のコードは、options変数を使用してパーサーに渡されたオプションにアクセスすることもできます。
述語コード中の中括弧は、バランスがとれていなければならないことに注意してください。
! { predicate }
:
述語はJavaScriptコードの一部で、あたかも関数の中にあるかのように実行される。これは、直前の式でラベル付けされた式のマッチ結果を引数として取得します。return文を使ってJavaScriptの値を返す必要があります。返された値が真偽値でfalseと評価された場合は、undefinedを返し、入力を消費しません。
述語の中のコードは、文法の最初にあるイニシャライザーで定義されたすべての変数と関数にアクセスすることができます。
述語の中のコードは、location関数を使って位置情報にアクセスすることもできます。これは次のようなオブジェクトを返します:
{
start: { offset: 23, line: 5, column: 6 },
end: { offset: 23, line: 5, column: 6 }
}
start プロパティと end プロパティはともに現在の解析位置を指す。offsetプロパティはゼロベースのインデックスとしてオフセットを含み、lineプロパティとcolumnプロパティは1ベースのインデックスとして行と列を含む。
述語の中のコードは、options変数を使ってパーサーに渡されたオプションにアクセスすることもできる。
述語のコード中の中括弧はバランスがとれていなければならないことに注意。
$ expression
:
式のマッチを試みる。マッチに成功した場合は、マッチ結果の代わりにマッチしたテキストを返します。
label : expression
:
式をマッチさせ、そのマッチ結果を与えられたラベルの下に記憶する。ラベルはJavaScriptの識別子でなければなりません。
保存されたマッチ結果は、アクションのJavaScriptコードからアクセスできます。
expression1 expression2 ... expressionn
:
一連の式をマッチさせ、そのマッチ結果を配列で返す。
expression { action }
:
式をマッチさせる。マッチに成功した場合はアクションを実行し、そうでない場合はマッチに失敗したとみなす。
アクションはJavaScriptコードの一部で、あたかも関数の中にあるかのように実行されます。直前の式でラベル付けされた式のマッチ結果を引数として受け取ります。アクションはreturn文を使ってJavaScriptの値を返す必要があります。この値が先行式のマッチ結果とみなされます。
エラーを示すために、アクション内部のコードは期待される関数を呼び出すことができます。この関数は2つのパラメータを取ります。現在の位置で何が期待されているかの説明と、オプションの位置情報です(デフォルトは位置が返すものです。)説明は、スローされた例外のメッセージの一部として使用されます。
アクションの中のコードはerror関数を呼び出すこともできます。この関数は2つのパラメータ、エラーメッセージとオプションの位置情報を受け取ります(デフォルトは位置情報が返すものです。)メッセージはスローされた例外で使用されます。
アクション内のコードは、文法冒頭のイニシャライザーで定義されたすべての変数と関数にアクセスできます。アクションコード内の中括弧は、バランスよく配置する必要があります。
アクション内部のコードは、text関数を使用して、式でマッチしたテキストにアクセスすることもできます。
アクションの中のコードは、location関数を使って位置情報にアクセスすることもできます。この関数は次のようなオブジェクトを返します:
{
start: { offset: 23, line: 5, column: 6 },
end: { offset: 25, line: 5, column: 8 }
}
start プロパティは式の開始位置を指し、end プロパティは式の終了位置を指す。offsetプロパティはゼロベースのインデックスとしてオフセットを含み、lineプロパティとcolumnプロパティは1ベースのインデックスとして行と列を含む。
アクション内部のコードは、options変数を使用してパーサーに渡されたオプションにアクセスすることもできます。
アクション・コード内の中括弧は、バランスがとれていなければならないことに注意してください。
expression1 / expression2 / ... / expressionn
:
最初の式とのマッチを試み、成功しなければ2番目の式を試すなど。最初にマッチした式のマッチ結果を返します。マッチする式がない場合は、マッチに失敗したとみなします。
Compatibility
パーサー・ジェネレーターも生成されたパーサーも、以下の環境でうまく動作するはずです:
- Node.js 0.10.0+
- Internet Explorer 8+
- Edge
- Firefox
- Chrome
- Safari
- Opera