如何结合不同类型的ELEM解析器(How to combine parsers with diffe

2019-08-17 16:31发布

我试图创建一个合并的正则表达式解析器和一个自定义分析器我有一个解析器。 我已经看了斯卡拉:如何解析器组合来自不同对象的组合 ,但这个问题和答案处理有相同类型的解析器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 。 如何结合这些解析器?

Answer 1:

我觉得这个回答有点一个负责任的,因为我提出和回答斯卡拉:如何解析器组合来自不同对象的组合 。

简单的回答是,你不能合并不同类型的Elem 。 不同的和优雅的方式来解决这个问题,使用^? 以增加额外的滤波正则表达式解析器。

这可能有助于在阅读了Combinator的解析在Scala编程:

解析器输入

有时,解析器读取令牌的流,而不是字符的原始序列。 然后单独的词法分析器用于生字符流转换为标记流。 所述类型的分析器输入端被定义为如下:

 type Input = Reader[Elem] 

类读者来自包scala.util.parsing.input 。 它类似于一个流,但还跟踪的所有它读取的元素的位置的。 类型Elem表示个别的输入元件。 它是一个抽象的类型构件Parsers性状:

 type Elem 

这意味着,子类和解析器subtraits需要实例化类Elem到正在解析的输入元素的类型。 例如, RegexParsersJavaTokenParsers修复Elem等于Char

所以Elem由词法分析器,这是负责拿刀砍你的输入流中,解析器要应对可能的最小令牌使用。 既然你要处理的正则表达式,你ElemChar

不过不用担心。 只是因为你的词法分析器给你Char s表示并不意味着你的解析器被套牢他们。 什么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
     ^


文章来源: How to combine parsers with different types of Elem