私が理解している限り、いくつかの例外を除いて、ほとんどの言語は文脈自由です。たとえば、C++ では乗算または乗算をa * b
表す場合があります。type * pointer_declaration
どちらが行われるかは、コンテキスト、つまり最初の識別子の意味によって異なります。もう 1 つの例はname
、VHDL でのプロダクションです。
enum_literal ::= char_literal | identifer
physical_literal ::= [num] unit_identifier
func_call ::= func_identifier [parenthized_args]
array_indexing ::= arr_name (index_expr)
name ::= func_call | physical_literal | enum_litral | array_indexing
構文形式が異なることがわかりますが、オプションのパラメーターが省略されている場合は一致する可能性がありますf
。
Scala プラグインの設計者と話していて、依存関係が変わったときに AST を再評価するために AST をビルドするということを知りました。AST がある場合は、ファイルを再解析する必要はありません。AST ファイルの内容を表示する価値もあります。ただし、文法が文脈依存の場合、AST は無効になります (f
別のファイルで定義された関数であり、後でユーザーが列挙型リテラルまたは未定義に再修飾したとします)。この場合、AST が変更されます。依存関係を変更するたびに、AST が変更されます。評価して作成方法を教えてほしいという別のオプションは、あいまいな AST を構築することです。
私の知る限り、パーサー コンビネーターはPEG のようなものです。最初に一致した生成を返すことであいまいさを隠し、f
私の文法では最初の選択肢であるため、関数呼び出しに一致します。最初の成功に頼るのではなく、次の選択肢に進むコンビネータを求めています。最終的に、一致するすべての選択肢のリストが返されます。それは私にあいまいさを返すでしょう。
あいまいなファイル コンテンツ ツリーをユーザーに表示する方法はわかりませんが、依存ファイルを再解析する必要がなくなります。また、現代の言語設計がこの問題をどのように解決するかを知りたいです。
あいまいなノードが解析され、結果のあいまいさが返されたら、パーサーを収束させたいと思います。なぜなら、それを超えて解析を進めname
たいからであり、あいまいさのたびにファイルの最後まで解析したくないからです。f(10)
単一の引数を指定した関数呼び出しや、後でインデックス付けされる配列を返す nullary 関数呼び出しのような状況によって、状況は複雑になります。そのため、f(10) は、func_call
直接または再帰的にarr_indexing -> name ~ (expr)
. そのため、 のようにいくつかの並列ルールのように曖昧になることはありませんfcall | literal
。一部のブランチは、再収束する前に 1 つのパーサーよりも長くなる場合がありますfcall ~ (expr) | fcall
。
どのように解決していきますか?あいまいなコンビネータを PEG に追加することは可能ですか?