0

我想这语义定向解析器组合

import scala.util.parsing.combinator._ 
def name = ident ^^ {case ident => if (ident.contains("a")) ident.toUpperCase else ident 

println(parseAll(name, "aa")) // parsed: AA 
println(parseAll(name, "bb")) 

与输出

[1.3] parsed: AA 
[1.3] parsed: bb 
[1.1] failure: `(' expected but `a' found 

aa 
^ 
[1.3] failure: end of input expected 

f1(aa) 
^

正如你看到的,第二解析失败。似乎第一次生产的失败停止了尝试第二种选择。我实际上需要依赖于第一个标识符的值来选择这个或那个解析器来继续。

回答

0

这是可以做到返回Failure,这将皮球传给后续替代(不failure混淆Failure,第二个将停止解析)

def name = new Parser[String] { 
    def apply(s: Input) = ident(s) match { 
    case Success(ident, rem) => if (ident.contains("a")) Success(ident.toUpperCase, rem) else Failure("identifier with 'a' expected", s) 
    case a => a 
    } 
} | ident 

这使的真实语义调度制作

def pkg(prefix: String): Parser[_] = "." ~> name ^^ {case arg => s"P:$prefix.$arg"} 
def function(fID: String): Parser[_] = "(" ~> name <~ ")" ^^ {case arg => s"F:$fID($arg)"} 
val env = Map("p1" -> pkg _, "p2" -> pkg _, "f1" -> function _) 

def name = new Parser[Any] { 
    def apply(s: Input) = ident(s) match { 
    case Success(ident, rem) => env.get(ident) match { 
     case Some(parser) => parser(ident)(rem) 
     case _ => Failure(s"object $ident not found", s) 
    } ; case a => a // how can we monade this identity? 
    } 
} | ident 

// test inputs 
List("aaa","f1(bb)","p1.p2.c","f1(f1(c))","f1(f1(p1.f1(bbb)))","aaa(bb(.cc(bbb)))") foreach { 
    input => println(s"$input => " + parseAll(name, input)) 
} 

这里名称被解析。解析器首先尝试一个标识符。它在语义上检查该标识符在上下文中是否为函数或包。如果没有,它会回落到简单的标识符分析器。这很愚蠢,但这是我要求的。演示解析是

aaa => [1.4] parsed: aaa 
f1(bb) => [1.7] parsed: F:f1(bb) 
p1.p2.c => [1.8] parsed: P:p1.P:p2.c 
f1(f1(c)) => [1.10] parsed: F:f1(F:f1(c)) 
f1(f1(p1.f1(bbb))) => [1.19] parsed: F:f1(F:f1(P:p1.F:f1(bbb))) 
aa(b) => [1.3] failure: end of input expected 

aa(b) 
^
f1(cc.dd) => [1.6] failure: `)' expected but `.' found 

f1(cc.dd) 
    ^

预期的错误:f1是唯一定义的函数和aa是不是其中之一。因此,它被作为标识符消耗,因此未消耗掉(b)。同样,cc作为简单标识符消耗,因为它不是定义的包。