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 trait 提供了从 Regex 到 Parser[Char] 的隐式转换,它在检查正则表达式匹配之前跳过任何前导空格。您可以使用

override val skipWhitespace = false

关闭此行为,或覆盖whiteSpace成员(它是另一个正则表达式)以提供您自己的自定义字符串。

这些选项在全局范围内有效,关闭空格跳过意味着所有正则表达式产品都会看到空格。

另一种选择是避免在需要空格的少数情况下使用正则表达式转换。我在 CSS 解析器中这样做,它忽略了大多数地方的注释,但在规则之前它需要读取它们以提取一些 javadoc 样式的元数据。

于 2010-07-28T01:34:29.763 回答
1

您是否考虑过在解析器之前使用词法分析器?

于 2010-08-07T16:33:18.147 回答