2

私はここしばらく Scala パーサー コンビネーターをいじっており、組み込み関数を使用して、適切に動作し、必要なことを最大限に実行する方法をいくつか学びました。

しかし、組み込み言語 (php や ruby​​ の erb など) を作成するにはどうすればよいでしょうか。実際のコードの埋め込み以外では、空白を無視しないようにする必要があります。

特定の正規表現一致までのすべてのテキストに一致する単純なパーサーを作成することができましたが、これを行うためのより良い、きれいな方法を探しています。おそらく、必要なものを実行する定義済みの関数がいくつかあります。

テスト言語は、次のようなテキストを解析します。

now: [[ millis; ]]
and now: [[; millis; ]]

次のコードによって生成されます。

package test

import scala.util.parsing.combinator.RegexParsers
import scala.util.matching.Regex

sealed abstract class Statement
case class Print(s: String) extends Statement
case class Millis() extends Statement

object SimpleLang extends RegexParsers {

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

  def until(s: String): Parser[String] = until(java.util.regex.Pattern.quote(s).r)

  def interpret(stats: List[Statement]): Unit = stats match {
    case Print(s) :: rest => {
      print(s)
      interpret(rest)
    }
    case Millis() :: rest => {
      print(System.currentTimeMillis)
      interpret(rest)
    }
    case Nil => ()
  }

  def apply(input: String) : List[Statement] = parseAll(beginning, input) match {
    case Success(tree,_) => tree
    case e: NoSuccess => throw new RuntimeException("Syntax error: " + e)
  }

  /** GRAMMAR **/

  def beginning = (
    "[[" ~> stats |
    until("[[") ~ "[[" ~ stats ^^ { 
      case s ~ _ ~ ss => Print(s) :: ss
    }
  )

  def stats = rep1sep(stat, ";")

  def stat = (
    "millis" ^^^ { Millis() } |
    "]]" ~> ( (until("[[") <~ "[[") | until("\\z".r)) ^^ {
      case s => Print(s)
    }
  )

  def main(args: Array[String]){
    val tree = SimpleLang("now: [[ millis; ]]\nand now: [[; millis; ]]")
    println(tree)
    interpret(tree)
  }

}
4

2 に答える 2

8

Scala の RegexParsers トレイトは、Regex から Parser[Char] への暗黙的な変換を提供します。これは、正規表現の一致をチェックする前に先頭の空白をスキップします。使用できます

override val skipWhitespace = false

この動作をオフにするか、whiteSpaceメンバー (別の正規表現) をオーバーライドして独自のカスタム文字列を提供します。

これらのオプションはグローバルに機能します。空白のスキップをオフにすると、すべての正規表現生成で空白が表示されます。

別のオプションは、空白が必要ないくつかのケースで正規表現変換を使用しないようにすることです。ここでは、ほとんどの場所でコメントを無視する CSS のパーサーでこれを行いましたが、ルールの直前にコメントを読み取って、javadoc スタイルのメタデータを抽出する必要があります。

于 2010-07-28T01:34:29.763 に答える
1

パーサーの前にレクサーを使用することを検討しましたか?

于 2010-08-07T16:33:18.147 に答える