Scalas/Haskells パーサー コンビネーターがプログラミング言語の解析に十分かどうか疑問に思っています。より具体的には、MiniJava 言語です。私は現在、コンパイラの構築を読んでおり、jflex と Java カップを使用するのは非常に面倒なので、代わりにパーサー コンビネータを使用できる/使用する必要があるかどうか疑問に思っています。MiniJava 構文は非常に小さいです。MiniJavas BNF: http://www.cambridge.org/us/features/052182060X/grammar.html
6 に答える
私はScalaを使ったことがありませんが、決定的なBNFが存在することでこれが簡単になります。
HaskellのText.ParserCombinators.Parsecに簡単に翻訳されます:
goal = do c <- mainClass
cs <- many classDeclaration
eof
return $ c:cs
mainClass = do token "class"
name <- identifier
...
など。PArrowsの翻訳も非常に簡単です。パーサーの前に明確な字句解析フェーズを設定する方が簡単な場合もありますが、それがなくても実行できます。
私は Scala のパーサー コンビネーターを使用して PL/SQL コードを解析しています。
少なくとも、Parsec には Java ライクな言語用のレクサーが組み込まれています。
lexer = makeTokenParser javaStyle
予約語は自分で定義する必要があります。
Scala のパーサーはバックトラッキング パーサーであるため、ほぼすべての BNF または EBNF を処理できます。ただし、入力の読み取りが非常に遅くなる可能性があるエッジケースがあることも意味します。
文法をLL(1) grammarに変更できる場合は、 ~! バックトラックを最小限に抑えるオペレーター。
文法はおそらく LL(1) に変換できますが、書かれているように、そうではありません。たとえば、Expression と Statement に First/First 競合があることを確認してください (リンクされた記事の最後でこれを調べてください)。
とにかく、アカデミックなプロジェクトならそれで十分です。実際のコンパイラーの場合は、より高速なパーサーが必要です。
Scala でのプログラミング(p. 647) は次のように述べています。
[Scala のパーサー コンビネーター フレームワーク] は、パーサー ジェネレーターよりも理解と適応がはるかに簡単であり、実際には、非常に大きな入力を解析する必要がない限り、速度の違いは問題にならないことがよくあります。
ソース コードを (理想的には)非常に大きな入力として分類しないので、それで十分なはずです。
Scala や Haskell のパーサー コンビネーター ライブラリは扱っていませんが、文法は問題ないようです。