将自定义标记生成器与Parsers子类连接

时间:2014-01-24 12:23:46

标签: scala parsing

当你已经拥有一个令牌列表(不是字符)时,我很难理解如何使用scala解析器组合器api。我已经看了TokenParsers的源代码,但是我无法理解“lexical”成员是什么以及如何插入我自己的Reader实现(或者其他方式来获取解析器使用的令牌)。

在线提供的示例(以及Odersky等人的“Scala编程”一书)没有说明如何将api与非字符令牌一起使用。一些例子表明,Parsers的子类必须将elem参数设置为令牌类型,但其中是来自哪个令牌? Reader [MyToken]输入参数在哪里?

只是为了澄清:词法分析已经完成。空白删除,分隔符,所有这些都已完成。我有一个令牌列表,只想使用解析器组合器的好处来创建一个AST。令牌看起来有点像这样:

sealed abstract class MyToken {
  val line : Int
  val col : Int
}
case class LPAREN ( line : Int, col : Int ) extends MyToken
case class RPAREN ( line : Int, col : Int ) extends MyToken

1 个答案:

答案 0 :(得分:3)

我最终想通了。 phrase()方法接受一个Reader参数,所以我可以包装我的令牌流并调用它。

class MyParsers extends Parsers {
  type Elem = MyToken

  def parse(tokens: Iterable[MyToken]): ParseResult[Any] = {
    val reader = new MyReader(tokens)
    phrase(myGrammarRule)(reader)
  }

  // ...etc...
}

sealed class MyReader(tokens : Iterable[MyToken]) extends Reader[MyToken] {
  def pos : Position = tokens.head
  def atEnd : Boolean = tokens.isEmpty
  def rest : Reader[MyToken] = new MyReader(tokens.tail)
  def first : MyToken = tokens.head
}

sealed abstract class MyToken extends Position {
  val _line : Int
  val _col : Int

  override def column = _col
  override def line = _line
  override def lineContents = ""
}

case class LPAREN ( _line : Int, _col : Int ) extends MyToken
case class RPAREN ( _line : Int, _col : Int ) extends MyToken

位置mixin很不错,因为它允许Parser在我的标记中使用已存在的位置信息,而无需添加任何粘合剂。