2010-07-21 82 views
2

如何在使用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)) 

回答

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 != "#"}) 
+0

我已经这样做了。我想按照问题中所述编写过滤器。该应用程序不删除评论,这只是解释问题的最简单方法。 – 2010-07-21 17:55:17

+0

我自己写的,然后回来,意识到你已经编辑!您可以拥有接受的答案,有趣的是代码如此相似。我用递归,你用了一个while循环,但除此之外他们几乎是相同的:-) – 2010-07-24 17:41:28

2

我现在已经完成了,这里是结果。关键的洞察是,解析器组合器的解析器使用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 
}