用嵌套的parens解析scala

时间:2011-02-03 22:18:01

标签: parsing scala

尝试解析像GroupParser.parse这样的嵌套表达式(“{{a} {{c} {d}}}”) 经过几个小时,我现在已经关注了很好地解析{a}的snipplet,但是

失败了
[1.5] failure: ``}'' expected but `{' found  
{{a}{{b}{c}}}
    ^

sealed abstract class Expr

case class ValueNode(value:String) extends Expr

object GroupParser extends StandardTokenParsers {
    lexical.delimiters ++= List("{","}")

    def vstring = ident ^^ { case s => ValueNode(s) }   
    def expr = ( vstring | parens ) 
    def parens:Parser[Expr] = "{" ~> expr  <~ "}"

    def parse(s:String) = {
        val tokens = new lexical.Scanner(s)
        phrase(expr)(tokens)
    }

}

任何提示?

3 个答案:

答案 0 :(得分:3)

问题不在于嵌套,而在于排序。你的语法允许在curlies中任意嵌套表达式,但是并不是说表达式可以排序,因此解析器无法处理{a}紧跟{{b} {c}}。您可以使用语法中的显式递归或使用http://www.scala-lang.org/api/current/scala/util/parsing/combinator/Parsers.html

中的一个rep变体对代码进行编码

答案 1 :(得分:1)

表达式可以重复多次吗?如果是这样,这将有效:

def expr = ( vstring | parens )+

然而,目前尚不清楚你的语法是什么,或者为什么你的例子可以被接受。

答案 2 :(得分:0)

这解析了你给出的两个例子:

import scala.util.parsing.combinator.syntactical._

sealed abstract class Expr

case class ValueNode(value:String) extends Expr

case class ValueListNode(value:List[Expr]) extends Expr

object GroupParser extends StandardTokenParsers {
  lexical.delimiters ++= List("{","}")

  def vstring = ident ^^ { case s => ValueNode(s) }   
  def parens:Parser[Expr] = "{" ~> ( expr )  <~ "}"
  def expr = vstring | parens

  def exprList:Parser[Expr] = "{" ~> rep1( expr | exprList ) <~ "}" ^^ {
    case l => {
      ValueListNode(l)
    }
  }

  def anyExpr = expr | exprList

  def parse(s:String) = {
    val tokens = new lexical.Scanner(s)
    phrase(anyExpr)(tokens)
  }

  def test(s: String) = {
    parse(s) match {
      case Success(tree, _) =>
        println("Tree: " + tree)
      case e: NoSuccess => Console.err.println(e)
    }
  }

  def main(args: Array[String]) = {
    test("{a}")
    test("{{a}}")
    test("{{a}{{b}{c}}}")
  }
}

成功输出:

Tree: ValueNode(a)
Tree: ValueNode(a)
Tree: ValueListNode(List(ValueNode(a), ValueListNode(List(ValueNode(b), ValueNode(c)))))