Scala:異なるオブジェクトからのパーサーコンビネーターを組み合わせる方法を尋ねて答えたので、私はこれに答えるのにいくらか責任があると感じています。
簡単な答えは、異なるタイプのを組み合わせることはできないということですElem
。この問題を解決するための別の洗練された方法は^?
、追加のフィルタリングで正規表現パーサーを拡張するために使用します。
ScalaでのプログラミングにおけるCombinatorParsingについて読むと役立つかもしれません:
パーサー入力
パーサーは、文字の生のシーケンスではなく、トークンのストリームを読み取る場合があります。次に、別の字句解析プログラムを使用して、生の文字のストリームをトークンのストリームに変換します。パーサー入力のタイプは次のように定義されます。
type Input = Reader[Elem]
クラスReaderはパッケージから取得されますscala.util.parsing.input
。これはStreamに似ていますが、読み取るすべての要素の位置を追跡します。タイプElem
は、個々の入力要素を表します。これは、Parsers
トレイトの抽象型メンバーです。
type Elem
これは、パーサーのサブクラスとサブトレイトがElem
、解析されている入力要素のタイプにクラスをインスタンス化する必要があることを意味します。たとえば、に等しくなるようにRegexParsers
修正JavaTokenParsers
します。Elem
Char
そのElem
ため、字句解析プログラムで使用されます。字句解析プログラムは、入力ストリームを、パーサーが処理する可能性のある最小のトークンに切り刻む役割を果たします。正規表現を扱いたいので、あなたElem
はChar
です。
しかし、心配しないでください。レクサーがsを提供するからといって、パーサーがそれらに固執してChar
いるわけではありません。正規表現から。への暗黙のコンバーターが提供されます。演算子(入力を完全にマップする)と演算子(入力を部分的にマップする)を使用して、それらをさらに変換できます。RegexParsers
Parser[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
^