从Scala解析器组合器中过滤令牌
问题描述:
如何在使用Scala解析器组合器时过滤从Lexer到我的解析器的令牌序列?从Scala解析器组合器中过滤令牌
让我解释一下 - 假设我有一个相当标准的Lexer模式(扩展为StdLexical
)和一个解析器(扩展为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))
答
你有没有考虑使用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 != "#"})
答
我现在已经完成了,这里是结果。关键的洞察是,解析器组合器的解析器使用scala.util.parsing.input.Reader
作为输入。所以我们需要一个包装Reader
的类,本身是一个Reader
,它在某些条件下过滤出条目。
我写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-21 17:55:17
我自己写的,然后回来,意识到你已经编辑!您可以拥有接受的答案,有趣的是代码如此相似。我用递归,你用了一个while循环,但除此之外他们几乎是相同的:-) – 2010-07-24 17:41:28