3

StandardTokenParsersベースのパーサーで正規表現を使用しようとしています。そのために、StdLexicalを次のようにサブクラス化しました。

class CustomLexical extends StdLexical{
  def regex(r: Regex): Parser[String] = new Parser[String] {
    def apply(in:Input) = r.findPrefixMatchOf(in.source.subSequence(in.offset, in.source.length)) match {
      case Some(matched) => Success(in.source.subSequence(in.offset, in.offset + matched.end).toString,
        in.drop(matched.end))
      case None => Failure("string matching regex `" + r + "' expected but " + in.first + " found", in)
    }
  }

  override def token: Parser[Token] =
    (   regex("[a-zA-Z]:\\\\[\\w\\\\?]* | /[\\w/]*".r)     ^^ { StringLit(_) }
      | identChar ~ rep( identChar | digit )               ^^ { case first ~ rest => processIdent(first :: rest mkString "") }
      | ...

しかし、これを利用するパーサーをどのように定義するかについて少し混乱しています。私は次のように定義されたパーサーを持っています:

def mTargetFolder: Parser[String] = "TargetFolder" ~> "=" ~> mFilePath

これは、有効なファイルパスを識別するために使用する必要があります。私はそれから試しました:

def mFilePath: Parser[String] = "[a-zA-Z]:\\\\[\\w\\\\?]* | /[\\w/]*".r

しかし、これは明らかに正しくありません。エラーが発生します:

scala: type mismatch;
 found   : scala.util.matching.Regex
 required: McfpDSL.this.Parser[String]
    def mFilePath: Parser[String] = "[a-zA-Z]:\\\\[\\w\\\\?]* | /[\\w/]*".r
                                                                          ^

StdLexicalサブクラスで作成された拡張機能を使用する適切な方法は何ですか?

4

2 に答える 2

5

本当にトークン ベースの解析を使用し、StdLexical を再利用したい場合は、"TargetFolder" の構文を更新して、等号の後の値が適切な文字列リテラルになるようにすることをお勧めします。つまり、パスを引用符で囲むようにします。その時点から、StdLexical を拡張する必要はもうありません。

次に、正規表現をパーサーに変換する問題が発生します。Scala にはすでにRegexParsersこれがあります (暗黙的に regexp を に変換します) が、残念ながら、トークンのストリームで作業している間に( in )Parser[String]のストリームで動作するため、ここで必要なものではありません。そのため、Regex から への独自の変換を定義する必要があります(ただし、字句レベルではなく構文レベルで、つまりトークン パーサーで)。Chartype Elem = CharRegexParsersParser[String]

import scala.util.parsing.combinator.syntactical._
import scala.util.matching.Regex
import scala.util.parsing.input._

object MyParser extends StandardTokenParsers {
  import lexical.StringLit
  def regexStringLit(r: Regex): Parser[String] = acceptMatch( 
    "string literal matching regex " + r, 
    { case StringLit( s ) if r.unapplySeq(s).isDefined => s }
  )
  lexical.delimiters += "="
  lexical.reserved += "TargetFolder"
  lazy val mTargetFolder: Parser[String] = "TargetFolder" ~> "=" ~> mFilePath
  lazy val mFilePath: Parser[String] = regexStringLit("([a-zA-Z]:\\\\[\\w\\\\?]*)|(/[\\w/]*)".r)  
  def parseTargetFolder( s: String ) = { mTargetFolder( new lexical.Scanner( s ) ) }
}

例:

scala> MyParser.parseTargetFolder("""TargetFolder = "c:\Dir1\Dir2" """)
res12: MyParser.ParseResult[String] = [1.31] parsed: c:\Dir1\Dir2

scala> MyParser.parseTargetFolder("""TargetFolder = "/Dir1/Dir2" """)
res13: MyParser.ParseResult[String] = [1.29] parsed: /Dir1/Dir2

scala> MyParser.parseTargetFolder("""TargetFolder = "Hello world" """)
res14: MyParser.ParseResult[String] =
[1.16] failure: identifier matching regex ([a-zA-Z]:\\[\w\\?]*)|(/[\w/]*) expected
TargetFolder = "Hello world"
           ^

ここで「ターゲットフォルダー」の正規表現も修正したことに注意してください。2つの選択肢の周りに括弧がなく、不要なスペースがありました。

于 2013-01-09T16:44:47.563 に答える
0

aから aregexを取得したい場合は、関数を呼び出すだけです。Parser[String]Regex

def p: Parser[String] = regex("".r)

またはregex、コンパイラーが自動的に呼び出すように暗黙的にします。

implicit def regex(r: Regex): Parser[String] = ...
// =>
def p: Parser[String] = "".r
于 2013-01-09T15:35:18.740 に答える