4

正規表現パーサーと私が持っているカスタムパーサーを組み合わせたパーサーを作成しようとしています。Scala:異なるオブジェクトからのパーサーコンビネーターを組み合わせる方法を見てきましたが、その質問と回答は同じタイプのパーサーを扱いElemます。

いくつかのRegexParsersと、文字列のルックアップを行うパーサーがあるとします。

trait NumbersParsers extends RegexParsers {
  def number = """\d+""".r
}

trait LookupParsers extends Parsers {
  type Elem = String
  def word = elem("word", (potential:String) => dictionary.exists(_.equals(x))
}

これらのパーサーを素朴に組み合わせると

object MyParser extends NumbersParsers with RegexParsers {
  def quantitive = number ~ word
}

のタイプが異なるため、明らかにタイプエラーが発生しElemます。これらのパーサーを組み合わせるにはどうすればよいですか?

4

1 に答える 1

4

Scala:異なるオブジェクトからのパーサーコンビネーターを組み合わせる方法を尋ねて答えたので、私はこれに答えるのにいくらか責任があると感じています。

簡単な答えは、異なるタイプのを組み合わせることはできないということですElem。この問題を解決するための別の洗練された方法は^?、追加のフィルタリングで正規表現パーサーを拡張するために使用します。

ScalaでのプログラミングにおけるCombinatorParsingについて読むと役立つかもしれません:

パーサー入力

パーサーは、文字の生のシーケンスではなく、トークンのストリームを読み取る場合があります。次に、別の字句解析プログラムを使用して、生の文字のストリームをトークンのストリームに変換します。パーサー入力のタイプは次のように定義されます。

type Input = Reader[Elem]   

クラスReaderはパッケージから取得されますscala.util.parsing.input。これはStreamに似ていますが、読み取るすべての要素の位置を追跡します。タイプElemは、個々の入力要素を表します。これは、Parsersトレイトの抽象型メンバーです。

type Elem

これは、パーサーのサブクラスとサブトレイトがElem、解析されている入力要素のタイプにクラスをインスタンス化する必要があることを意味します。たとえば、に等しくなるようにRegexParsers修正JavaTokenParsersします。ElemChar

そのElemため、字句解析プログラムで使用されます。字句解析プログラムは、入力ストリームを、パーサーが処理する可能性のある最小のトークンに切り刻む役割を果たします。正規表現を扱いたいので、あなたElemCharです。

しかし、心配しないでください。レクサーがsを提供するからといって、パーサーがそれらに固執してCharいるわけではありません。正規表現から。への暗黙のコンバーターが提供されます。演算子(入力を完全にマップする)と演算子(入力を部分的にマップする)を使用して、それらをさらに変換できます。RegexParsersParser[String]^^^?

それらをパーサーに組み込みましょう:

import scala.util.parsing.combinator._

scala> val dictionary = Map("Foo" -> "x")
dictionary: scala.collection.immutable.Map[String,String] = Map(Foo -> x)

scala> trait NumbersParsers extends RegexParsers {
     |   def number: Parser[Int] = """\d+""".r ^^ { _.toInt }
     | }
defined trait NumbersParsers

scala> trait LookupParsers extends RegexParsers {
     |   def token: Parser[String] = """\w+""".r
     |   def word =
     |     token ^? ({
     |       case x if dictionary.contains(x) => x
     |     }, {
     |       case s => s + " is not found in the dictionary!"
     |     })
     | }
defined trait LookupParsers

scala> object MyParser extends NumbersParsers with LookupParsers {
     |   def quantitive = number ~ word
     |   
     |   def main(args: Array[String]) {
     |     println(parseAll(quantitive, args(0) ))
     |   }
     | }
defined module MyParser

scala> MyParser.main(Array("1 Foo"))
[1.6] parsed: (1~Foo)

scala> MyParser.main(Array("Foo"))
[1.1] failure: string matching regex `\d+' expected but `F' found

Foo
^

scala> MyParser.main(Array("2 Bar"))
[1.6] failure: Bar is not found in the dictionary!

2 Bar
     ^
于 2013-03-17T08:53:34.687 に答える