pegjsはシンプルで強力です。 大好きです! ドキュメントでカバーされていないいくつかの質問があります:
私はこれを解析していますが、これは機能しますが、ルールは厄介なようです:
f = x => x * x
オペレーターと言うように委任した場合、値を渡す方法はありません。 ValuesOperatorsおよびor =および=>を作成すると、少しクリーンになりますが、トップレベルでは、どちらであるかを確認する必要があります。 JavaScriptの例では、{type: "Literal"、value:...}の使用が見られます。 それは情報を元に戻すための最良の方法ですか?
= values:Values body:(_ "=>" _ Expression)? assign:(_ "=" _ Expression)? {
if (body && body.length > 0) {
return new Function(values, body[3]);
} else if (assign) {
return new Assignment(values, assign[3]);
} else {
return values;
}
}
ありがとう!
マイク
文法では、ルールを理解することが不可欠です。 そして、あなたはサブだけを提供しています..これは私には明らかではありません、どのようにそれが機械に明確であることができますか?
LALR文法は書くのが非常に難しいですが、LRよりも簡単で、LLよりも簡単です。
PEG文法は、効率的に書くのが最も難しい芽を書くのが簡単です。
正しいおもちゃを使っていますか? 優れたPEG文法があれば、トランスパイラーを作成したり、ルールを解釈するのと同じくらい簡単に解釈したりできるはずです。
仮想マシンでのボックス化/ボックス化解除を知っていますか?
割り当ての左側にvalues
を設定するにはどうすればよいですか? あなたがこれを持っているので: body:(_ "=>" _ Expression)?
は?で終わった
あなたの文法でvalues
は何を意味しますか? L値とは何か知ってい
文法を意味的に近くに保つ必要があります。 場合によってはPEGでは難しいです。 { type: "Literal", value: ... }
はまさにASTで必要なものです。 http://astexplorer.net/を見て
実験に使い始めたばかりなので、名前の一部が間違っています:)簡単なLL(1)パーサーをいくつか作成しましたが、しばらく経ちました。 私は、決定を処理するための最良の方法が何であるかを知りたいだけです。 この構文を単純化します。
a = b
また
x => x * x
このようなことをする方が適切ですか?
AssignmentOrFunction
= ident:識別子演算子:IdentOperator {
if(operator.type === "Function"){
..。
}
IdentOperator
= "="! ">" {return {type: "Assignment"; }}
/ "=>" {...}
参考までに、「値」はアイテムのリストを意味するために使用した用語でした。タプルとして使用する場合は値になりますが、関数の引数を定義するために使用する場合は変数になります。 たとえば(2 + 3)。
御時間ありがとうございます!
@mikeaustinそれはあなたのものです:-)
文法を書くことはすべて削減についてです。 一番上はステートメントです。 それは感覚のようなものです、あなたが知っている、あなたはLL文法を持っています:-)
ある意味で文法を定義するのはあなたの責任です(申し訳ありませんが、私は英語に問題があります:-D時々)
どのようにAssignmentOrFunctionを処理しますか? これは基本的に多くの言語のステートメントと同じですが、 R値にすることもできます。
反対側
= "=" !">" { return { type: "Assignment"; } }
/ "=>" { ... }
次のように書く方がよい
= "=>" { ... }
/ "=" { return { type: "Assignment"; } }
私が間違っているかもしれませんが..しかし、これはあなたがそれほど重要ではない断片にあなたの文を分割しているように見えます。 文脈がなければ、これを何を評価するかはそれほど重要ではありません。
PEGは、到達不能なルールを簡単に記述したり、文を盗んで誤って評価するルールを記述したりできるため、作成が非常に困難です。したがって、初心者の場合は、左側に文を、右側に必要なASTを常に配置する必要があります。文法規則よりも何倍も自動化されたテスト。 私を信じてください、あなたは1つのルールを変更し、あなたのパーサー全体が壊れます。
そしてもちろん、何度も何度も遊んだり、何かを書いたりする必要があります。PEGを使用して効果的な式計算機を作成することは簡単ではありません。いくつかのレベルの優先順位に注意してください。一般的な構文解析にはPEGの方が適しています。
あなたが本当に作りたいものを推測することは非常に難しいですが、私はあなたが文法をより果たすべき推測することができますので、あなたは、あなたの質問に私に多くのコンテキストを与えていない、ANTLR、学習のための素晴らしいツールは、GoldParser(LALR)(私があります最初のおもちゃ:-))、十分にテストされ、最も効率的ですが、トークナイザー/パーサー(古いlexとyacc、新しいflexとbison)に分割されたいくつかの古い学校のパーサー、それらの多くのポート..
PEGは最も単純なように見えます。 本当にそうです。 しかし、それは常に最も危険です...
どうもありがとうございました! ああ、私はpegjsのGoogleグループを見つけましたが、それが開発セクションにあったので気づきませんでした。 他に質問がある場合は、代わりに必ず行きます。
はい、代入「x = y」は_statement_ですが、「x => x * x」は、「x == y」などと同様に、_expression_の一部にすることができます。「=」は特殊なケースです。通常の演算子ではないという意味で「=>」です。 もっと練習して、例をもっと詳しく見ていきます。 電卓よりは大きいが、他の例よりは小さい例があったらいいのにと思います。 多分私が進歩すればそれは例かもしれません:)
私のプロジェクトでは、JSにトランスパイルするための簡単な言語を書きたいと思います。 基本は、外部の字句スコープのメソッド(DylanやCLOSのようなモンキーパッチはありませんが、マルチメソッドはありません)、キーワード引数、ADT、場合によってはオプションの静的型付けです。 「シンプル」とは、すべてが連携して機能することを意味し、何かを行う方法は1つだけです。 何かを単純にすることは_難しい_ことがあります。
また、ネイティブ構文の恩恵を受ける可能性のあるadtやmultimethodsなどのライブラリもあります。 これらは実際にはsweetで実現できますが、 TypeScriptには「--strictNullChecks」のようなオプションがあり、インライン共用体型をサポートしますが、ここでもJSを拡張して、すべての悪いことを残します(暗黙の強制、文字列の連結、スコープの巻き上げなどの「+」)。
繰り返しになりますが、すべての助けに感謝します!
マイク
私は、後戻りがなく、貪欲であることは、「現在どこにいても」作業しなければならないことを意味すると想定していましたが、そうではありません。 わーい!
貪欲とは、一致するものが見つかった場合にそれを取得することを意味しますよね? ただし、ルール全体が一致しない場合は、次の一致で最初から再開されます。 これにより、私が最初にやろうとしていた方法よりもはるかに簡単になります。
x, y = 2 + 3.foo + "foo", 5 * 2
正規表現などとは別に代入を照合できる場合、これはかなり簡単です。
= Assignment
/ Expression
Assignment
= vars:Variables _ "=" _ expr:Expression
Variables
= head:Identifier tail:(_ "," _ Identifier)*
...
@mikeaustin PEGは、式で一致する最初のパターンが自動的に一致することを意味する選択順序を持っています。 @langpavelの例は、 =>
よりも=
=>
優先順位を表す良い方法です。 「表現になる可能性のあるこのテキストをすべて取得して後で理解する」のではなく、「これらの1つ」の観点から表現が何であるかについてもっと考えたいと思うかもしれません。
= FunctionExpression
/ Assignment
/ Value
実演するために、私はあなたが遊ぶことができるテスト文法を作成しました。 少しうるさいですが、余分な空白や演算子を許可するなどのいくつかのことを無視して、かなりシンプルにしようとしました。 魔法が発生するExpression
ブロックに注意してください。 また、「これらの多く」の状況を処理する方法として、 SubExpression
やExpressionList
などを使用しました。 そのパターンは、リストの区切り文字と項目を分離しておくのに適しています。
いずれの場合も、一致する種類ごとに1つの項目を用意することで、文法を単純に保つようにしています。 可能なすべての組み合わせで1つの大きな一致シーケンスを持つように書き直すことができるため、冗長性がありますが、それを追跡するのは難しく、PEGが順序付けられた選択で排除できるあいまいさを残します。 それが役に立てば幸い。
テスト文法を見てみましょう、ありがとう! JavaScriptの文法はかなり大きいので、言語の最小限のサブセットを確認するのに役立ちます。
@dmsnell最近、ルールを削除し、JavaScript文法にいくつかの新しいルールを追加することで、多くのことを学びました。最新のものは、 impal.pegjsで確認できます。 省略構文[、、]、一部の演算子、シーケンス式などを削除し、タプル構文(1、2)と範囲構文1..5を追加しました。 浮動小数点数は、リテラル範囲を解析しやすくするために、両側に小数が必要です。
私は最近多くのランタイムに取り組んでいますが、実際にJavaScriptを発行するためにパーサーに戻りたいと思っています。 私は仕事の合間にいるので、少し時間があります:)拡張メソッド、名前付きパラメーター、特性とミックスイン、演算子のオーバーロード、リテラルのタプルと範囲の構文を使用して、JavaScriptのダイアレクトをクリーンアップするためのいくつかのアイデア。
再度、感謝します!
マイク
最も参考になるコメント
私は、後戻りがなく、貪欲であることは、「現在どこにいても」作業しなければならないことを意味すると想定していましたが、そうではありません。 わーい!
貪欲とは、一致するものが見つかった場合にそれを取得することを意味しますよね? ただし、ルール全体が一致しない場合は、次の一致で最初から再開されます。 これにより、私が最初にやろうとしていた方法よりもはるかに簡単になります。
x, y = 2 + 3.foo + "foo", 5 * 2
正規表現などとは別に代入を照合できる場合、これはかなり簡単です。