私は DSL を作成しており、Scala のパーサー コンビネーター ライブラリを使用して DSL を解析しています。DSL は、Ruby に似た単純な構文に従います。ソース ファイルには、次のような一連のブロックを含めることができます。
create_model do
at 0,0,0
end
DSL では、行末はステートメントのターミネーターとして効果的に使用されるため、重要です。
次のような Scala パーサーを作成しました。
class ML3D extends JavaTokenParsers {
override val whiteSpace = """[ \t]+""".r
def model: Parser[Any] = commandList
def commandList: Parser[Any] = rep(commandBlock)
def commandBlock: Parser[Any] = command~"do"~eol~statementList~"end"
def eol: Parser[Any] = """(\r?\n)+""".r
def command: Parser[Any] = commandName~opt(commandLabel)
def commandName: Parser[Any] = ident
def commandLabel: Parser[Any] = stringLiteral
def statementList: Parser[Any] = rep(statement)
def statement: Parser[Any] = functionName~argumentList~eol
def functionName: Parser[Any] = ident
def argumentList: Parser[Any] = repsep(argument, ",")
def argument: Parser[Any] = stringLiteral | constant
def constant: Parser[Any] = wholeNumber | floatingPointNumber
}
行末は重要なwhiteSpace
ので、(新しい行を空白として扱って無視するのではなく) スペースとタブのみを空白として扱うようにオーバーライドしました。
の「終了」ステートメントを除いて、これは機能しcommandBlock
ます。私のソース ファイルには末尾の改行が含まれているため、パーサーはキーワードend
の後に改行を期待していたのに、改行を取得したと不平を言います。end
そこでcommandBlock
、 の定義を次のように変更しました。
def commandBlock: Parser[Any] = command~"do"~eol~statementList~"end"~opt(eol)
(つまり、「end」の後にオプションの新しい行を追加しました)。
しかし、ソース ファイルを解析すると、次のエラーが表示されます。
[4.1] failure: `end' expected but `' found
これは、末尾の改行を吸い込んだ後、パーサーが無効であると考える空の文字列に遭遇したためだと思いますが、なぜこれを行っているのかわかりません。
これを修正する方法に関するヒントはありますか?Scala のパーサー コンビネーター ライブラリから間違ったパーサーを拡張する可能性があるため、重要な改行文字を含む言語定義を作成する方法についての提案も歓迎します。