2

Scala パーサー コンビネーターを使用しているときに、レクサーからパーサーへの一連のトークンをフィルター処理するにはどうすればよいですか?

説明させてください - Lexer (extending StdLexical) と Parser ( extending ) のかなり標準的なパターンがあるとしStdTokenParsersます。lexer は一連の文字を一連のトークンに変換し、次にパーサーは一連のトークンを抽象構文木 (タイプExpr) に変換します。

ストリームのどこにでも発生する可能性のあるいくつかのトークンをフィルターで除外するオプションが必要であると判断したため、これらのトークンを削除するためにレクサーとパーサーの間に収まる関数が必要です。たとえば、レクサーでコメントをトークン化し、後でこれらのコメントを除外することができます。

このフィルターを作成する最良の方法は何ですか? これは、パーサー コンビネーターのイディオムを使用できますが、そうする必要はありません。

サンプルの現在のコード:

 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 に答える