だから私はパーサーをやっていて、速度よりも柔軟性を優先し、文法を簡単に書きたいと思っています。 .)
トークンの固定セット (例: PLUS、DECIMAL、STRING_LIT、NAME など) を使用して手作業でコード化されたレクサーがあり、現在、3 つのタイプのルールがあります。
- TokenRule: 特定のトークンに一致
- SequenceRule: 規則の順序付けられたリストに一致します
- GroupRule: リストの任意のルールに一致
たとえば、トークン名 (おおよそ /[A-Za-z][A-Za-z0-9_]*/) に一致する TokenRule 'varAccess' と [式、TokenRule(PLUS)、式]。
式は、「割り当て」または「varAccess」のいずれかに一致する GroupRule です (私がテストしている実際のルールセットはもう少し完全ですが、例ではそれで十分です)
しかし、今、私が解析したいとしましょう
var1 = var2
そして、パーサーがルール Expression で始まるとしましょう (それらが定義される順序は重要ではありません - 優先度は後で解決されます)。そして、GroupRule 式が最初に「代入」を試みるとしましょう。次に、「式」は「代入」で一致する最初のルールであるため、式を再度解析しようとします。スタックがいっぱいになり、コンピューターが - 予想どおり - キラキラした segfault で単にあきらめるまで、同様の処理が繰り返されます。
だから私がしたことは - SequenceRules は最初のルールに「葉」として自分自身を追加し、ルート以外のルールになります。ルート規則は、パーサーが最初に試行する規則です。それらのいずれかが適用されて一致すると、一致するまで、各リーフを 1 つずつサブ適用しようとします。次に、一致するリーフのリーフを試行し、一致するものがなくなるまで試行します。
次のような式を解析できるように
var1 = var2 = var3 = var4
ちょうどいい =) さて、興味深いものです。このコード:
var1 = (var2 + var3)
解析しません。何が起こるかというと、var1 が解析され (varAccess)、代入がサブ適用され、式が検索され、「括弧」が試行され、開始され、「(」の後の式が検索され、var2 が検出され、「+」がチョークされます。 ')' を予期していたためです。
「var2 + var3」と一致しないのはなぜですか? (そして、質問する前に、「追加」SequenceRule があります)。'add' はルート規則ではなく (parse-expression-beginning-with-expression などによる無限再帰を避けるため)、葉は SequenceRules でテストされないため、そうでなければ次のようなものを解析します。
reader readLine() println()
なので
reader (readLine() println())
(たとえば、'1 = 3' は add が期待する式であり、varAccess a のリーフです)
一方、左結合にしたいのですが、たとえば、次のように解析します
(reader readLine()) println()
とにかく、SequenceRules 内で「1 + 2」などの式を解析できるはずであるという問題が発生しました。何をすべきか?SequenceRules が TokenRule で始まる場合、それに含まれる GroupRules がリーフについてテストされるという特別なケースを追加しますか? その特定の例の外でも、それは理にかなっていますか? または、葉についてテストする必要があるかどうかを、SequenceRule の各要素で指定できるようにする必要がありますか? あなたの考えを教えてください(システム全体を捨てることを除いて - それはおそらく数ヶ月以内に起こります)
PS: どうか、どうか、「この 400 ページの本を読みに行ってください。さもないと、私たちの時間にふさわしくありません」などと答えないでください。わかった?前もって感謝します。