16

私は 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 のパーサー コンビネーター ライブラリから間違ったパーサーを拡張する可能性があるため、重要な改行文字を含む言語定義を作成する方法についての提案も歓迎します。

4

2 に答える 2

9

どちらの方法でも同じエラーが発生しますが、誤解していると思います。それが言っているのは、 を期待しているということですendが、すでに入力の最後に達しています。

そして、それが起こっている理由は、それendが声明として読まれているからです。これを解決する良い方法があると確信していますが、私は Scala パーサーの経験が十分ではありません。スキャン部分でトークンパーサーを使用する方法があるようですが、標準のトークンパーサーが改行を空白として扱わないようにする方法がわかりませんでした。

したがって、ここに代替案があります:

import scala.util.parsing.combinator.JavaTokenParsers

class ML3D extends JavaTokenParsers {
  override val whiteSpace = """[ \t]+""".r
  def keywords: Parser[Any] = "do" | "end"
  def identifier: Parser[Any] = not(keywords)~ident

  def model: Parser[Any] = commandList
  def commandList: Parser[Any] = rep(commandBlock)
  def commandBlock: Parser[Any] = command~"do"~eol~statementList~"end"~opt(eol)
  def eol: Parser[Any] = """(\r?\n)+""".r
  def command: Parser[Any] = commandName~opt(commandLabel)
  def commandName: Parser[Any] = identifier
  def commandLabel: Parser[Any] = stringLiteral
  def statementList: Parser[Any] = rep(statement)
  def statement: Parser[Any] = functionName~argumentList~eol
  def functionName: Parser[Any] = identifier
  def argumentList: Parser[Any] = repsep(argument, ",")
  def argument: Parser[Any] = stringLiteral | constant
  def constant: Parser[Any] = wholeNumber | floatingPointNumber
}
于 2010-03-05T02:28:20.217 に答える
0

デフォルトが である (正規表現)overrideか、正規表現で容易に達成できる以上の制御が必要な場合は、メソッドのいずれかを使用できます。これらのメンバーは両方とも、JavaTokenParsers の基本クラスである RegexParsers で発生します。protected val whiteSpace"""\s+""".roverrideprotected def handleWhiteSpace(...)

于 2010-03-04T21:00:50.380 に答える