4

我正在尝试创建一个结合了 Regex 解析器和我拥有的自定义解析器的解析器。我看过Scala: How to combine parser combinators from different objects,但那个问题和答案处理的是具有相同类型的解析器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: How to combine parser combinators from different objects以来,我觉得有责任回答这个问题。

快速的答案是,你不能组合不同类型的Elem. 解决此问题的一种不同而优雅的方法是使用^?额外的过滤来增强正则表达式解析器。

阅读Scala 编程中的Combinator Parsing可能会有所帮助:

解析器输入

有时,解析器会读取标记流而不是原始字符序列。然后使用单独的词法分析器将原始字符流转换为标记流。解析器输入的类型定义如下:

type Input = Reader[Elem]   

类 Reader 来自包scala.util.parsing.input。它类似于 Stream,但也跟踪它读取的所有元素的位置。该类型Elem表示单个输入元素。它是Parserstrait 的抽象类型成员:

type Elem

这意味着解析器的子类和子特征需要将类实例化为Elem正在解析的输入元素的类型。例如,RegexParsersJavaTokenParsers固定Elem为等于Char

SoElem被词法分析器使用,它负责将输入流分割成解析器想要处理的最小可能的标记。由于您要处理正则表达式,因此您的Elemis Char

但别担心。仅仅因为你的词法分析器给了你Chars 并不意味着你的解析器也被它们困住了。给你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
     ^
于 2013-03-17T08:53:34.687 回答