11

スコープを定義するためにインデントを使用する言語を解析するために、パーサーとレクサーのルールをどのように定義しますか。

私はすでにググって、字句解析器で INDENT および DEDENT トークンを生成することによってそれを解析するための巧妙なアプローチを見つけました。

この問題をさらに掘り下げて、何か興味深いことがあれば回答を投稿しますが、この問題に対する他のアプローチも見てみたいと思います。

編集:チャーリーが指摘したように、同じではないにしても、非常によく似た別のスレッドがすでにあります。私の投稿は削除されるべきですか?

4

2 に答える 2

11

これは、レクサーとパーサーに使用するテクノロジーに依存するため、一種の仮説ですが、最も簡単な方法は、C の中括弧に類似した BEGINBLOCK および ENDBLOCK トークンを使用することです。レクサーが必要とする「オフサイド規則」を使用するインデント レベルのスタックを追跡します。インデント レベルが上がると、パーサーに対して BEGINBLOCK を発行します。インデント レベルが減少すると、ENDBLOCK を発行し、スタックからレベルをポップします。

これについては、SOに関する別の議論があります。

于 2008-12-10T17:48:55.130 に答える
1

また、lexer のどこかで最初の行の前にある ident アイテムの数を追跡し、それをパーサーに渡すこともできます。最も興味深い部分は、それをパーサーに正しく渡そうとすることです:)パーサーが先読みを使用している場合(ここでは、パーサーが実際に1つでも一致する前に可変数のトークンを照会する可能性があることを意味します)、1つのグローバル変数を介してそれを渡そうとするようです非常に悪い考えです(パーサーがまだ前の行を解析しようとしている間に、レクサーが次の行でスリップしてインデントカウンターの値を変更する可能性があるため)。また、他の多くの場合、グローバルは悪です;) インデントカウンターを使用して、最初の行の「実際の」トークンをマークする方が合理的です。正確な例を示すことはできません (もしあれば、どのパーサーとレクサージェネレーターを使用するのかさえわかりません... )しかし、最初の行のトークンにデータを保存するようなもの(パーサーからそのようなトークンを簡単に取得できない場合は快適ではない可能性があります)またはカスタムデータを保存する(トークンをインデントにリンクするマップ、ソースコードのすべての行がインデックスとして配置される配列要素値としてのインデント値) で十分なようです。このアプローチの欠点の 1 つは、ident 値を区別し、それに基づいて動作を変更する必要があるパーサーがさらに複雑になることです。JavaCC の LOOKAHEAD({ yourConditionInJava }) のようなものがここで機能する可能性がありますが、このアプローチの欠点の 1 つは、ident 値を区別し、それに基づいて動作を変更する必要があるパーサーがさらに複雑になることです。JavaCC の LOOKAHEAD({ yourConditionInJava }) のようなものがここで機能する可能性がありますが、このアプローチの欠点の 1 つは、ident 値を区別し、それに基づいて動作を変更する必要があるパーサーがさらに複雑になることです。JavaCC の LOOKAHEAD({ yourConditionInJava }) のようなものがここで機能する可能性がありますが、あまり良い考えではありません。あなたのアプローチに多くの追加のトークンを使用することは、それほど悪いことではないようです:)

別の方法として、この 2 つのアプローチを組み合わせることをお勧めします。インデントカウンターが次の行で値を変更した場合にのみ、追加のトークンを生成できます。人工的な BEGIN および END トークンのようなものです。このようにして、レクサーからパーサーに供給されるストリーム内の「人工」トークンの数を減らすことができます。追加のトークンを理解するには、パーサーの文法だけを調整する必要があります...

私はこれを試しませんでした (そのような言語の解析に関する実際の経験はありません)。可能な解決策について私の考えを共有しただけです。この種の言語用に既に構築されたパーサーをチェックすることは、あなたにとって大きな価値があります。オープンソースはあなたの友達です ;)

于 2008-12-10T17:18:57.983 に答える