代码之家  ›  专栏  ›  技术社区  ›  Nick Fortescue

从Scala解析器组合器过滤令牌

  •  2
  • Nick Fortescue  · 技术社区  · 15 年前

    当使用Scala解析器组合器时,如何过滤从Lexer到解析器的令牌序列?

    StdLexical StdTokenParsers ). lexer将字符序列转换为令牌序列,然后解析器将令牌序列转换为抽象语法树(类型为 Expr

    我决定一些标记,可能出现在流中的任何地方,我想有过滤掉的选项,所以我想一个函数,可以在Lexer和解析器之间删除这些标记。例如,我可能希望lexer标记注释,然后稍后过滤掉这些注释。

    当前代码示例:

     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))
    
    2 回复  |  直到 15 年前
        1
  •  1
  •   Magnus    15 年前

    你考虑过用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 != "#"})
    
        2
  •  2
  •   Nick Fortescue    15 年前

    我已经做了,下面是结果。关键的洞察是来自解析器组合器的解析器使用 scala.util.parsing.input.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
    }
    
    推荐文章