2

使用 Scala 解析器组合器时,如何过滤从 Lexer 到 Parser 的标记序列?

让我解释一下——假设我有相当标准的 Lexer(扩展StdLexical)和 Parser(扩展StdTokenParsers)模式。词法分析器将字符序列转换为标记序列,然后解析器将标记序列转换为抽象语法树(类型为Expr)。

我决定一些可能出现在流中任何位置的标记,我希望可以选择过滤掉,所以我想要一个适合 Lexer 和 Parser 之间的函数来删除这些标记。例如,我可能希望词法分析器标记注释,然后过滤掉这些注释。

编写此过滤器的最佳方法是什么?这可以使用解析器组合成语,但不是必须的。

示例当前代码:

 val reader = new PagedSeqReader(PagedSeq.fromReader(reader))
 val tokens = new MyParser.lexical.Scanner(reader)
 val parse = MyParser.phrase(parser)(tokens)

我希望能够写出这样的东西:

 val reader = new PagedSeqReader(PagedSeq.fromReader(reader))
 val tokens = new MyParser.lexical.Scanner(reader)
 val parse = MyParser.phrase(parser)(filter(tokens))
4

2 回答 2

2

我现在已经完成了,这是结果。关键的见解是解析器组合器中的解析器使用 ascala.util.parsing.input.Reader作为输入。所以我们需要一个包装 a 的类,Reader它本身就是Reader在某些条件下过滤掉条目的 a。

我写了Reader这样的构造,它会跳过所有不需要的条目,并在第一个好的条目或结尾处停止。然后每个调用都被委托给原始读取器,除了 rest依次构造另一个 TokenFilter 之外。

import scala.util.parsing.input._

class Filter[T](parent : Reader[T], exclude : T=>Boolean) extends Reader[T] {
  private val start = nextOk(parent)
  def nextOk(r : Reader[T]) : Reader[T] =
    if(r.atEnd) r else (if (exclude(r.first)) nextOk(r.rest) else r)

  override def source = start.source
  override def offset: Int = start.offset
  override def first: T = start.first
  override def rest: Reader[T] = new Filter(start.rest, exclude)
  override def pos: Position = start.pos
  override def atEnd = start.atEnd
}
于 2010-07-24T17:38:15.987 回答
1

您是否考虑过使用 RegexParsers 删除空格和注释?

编辑

你可以做一个简单的过滤器

import scala.util.parsing.input._

object ReaderFilter {
  def filter[T](reader: Reader[T], check: T => Boolean): Reader[T] = {
    new Reader[T] {
      var orig = reader
      def first = { trim; orig.first }
      def atEnd = { trim; orig.atEnd }
      def rest: Reader[T] = { trim; ReaderFilter.filter(orig.rest, check) }
      def pos = orig.pos
      private def trim = {
        while (!orig.atEnd && !check(orig.first))
          orig = orig.rest
      }
    }
  }
}

并以这种方式使用它(删除“#”的标记):

val tokens = ReaderFilter.filter(new MyParser.lexical.Scanner(reader), 
          {t:ExprParser.lexical.Token => t.chars != "#"})
于 2010-07-21T11:43:35.083 回答