2011-11-12 40 views
1

有人可以帮助我理解以下行为: parseAll (parseIf, "If bla blablaa")应导致is expected。相反,我总是得到string matching regex 'is\b' expected but 'b' found。 我想它与空格有关,因为" If bla is blablaa"(注意开始处的空白)会导致相同的行为。我用StandardTokenParsers试了一下,一切正常。但STP不幸的是不支持正则表达式。 后续问题:我将如何修改RegexParsers,以便使用一系列字符串而不是一系列字符?这将使错误报告更容易。RegexParsers的自定义错误

lazy val parseIf = roleGiverIf ~ giverRole 

lazy val roleGiverIf = 
    kwIf ~> identifier | failure("""A rule must begin with if""") 
lazy val giverRole = 
    kwIs ~> identifier | failure("""is expected""") 

lazy val keyword = 
    kwIf | kwAnd | kwThen | kwOf | kwIs | kwFrom | kwTo 

lazy val identifier = 
    not(keyword) ~ roleEntityLiteral 
// ... 

def roleEntityLiteral: Parser[String] = 
    """([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})\S*""".r 
def kwIf: Parser[String] = "If\\b".r 
def kwIs: Parser[String] = "is\\b".r 

// ... 

parseAll(parseIf, "If bla blablaa") match { 
    case Success(parseIf, _) => println(parseIf) 
    case Failure(msg, _) => println("Failure: " + msg) 
    case Error(msg, _) => println("Error: " + msg) 

回答

0

这个问题很奇怪。当您拨打|并且双方都失败时,发生故障的一方上一个被选中,有利于左侧。

当您尝试直接使用giverRole解析时,它会生成您期望的结果。如果在失败之前添加成功的匹配,它会产生您看到的结果。

原因很微妙 - 我只通过在所有解析器上使用log声明来发现它。要了解它,你必须明白RegexParser跳过空格。具体来说,空格accept上被跳过。因为failure不叫accept,它不会跳过空格。

虽然kwIs故障发生在b,作为空间跳过的failure失败If后会发生上的空间。这里:

If bla blablaa 
^kwIs fails here 
^failure fails here 

因此,kwIs上的错误信息优先于我提到​​的规则。

您可以通过使解析器跳过空格而不匹配任何内容来解决此问题。这种模式总是匹配很重要,否则你会得到一个更令人困惑的错误消息。这里有一个建议,我觉得作品:

"\\b|$".r ~ failure("is expected") 

另一种解决方案是使用acceptIfacceptMatch而不是使用正则表达式隐含接受,在这种情况下,你可以提供一个量身定制的错误消息。

+0

我写了一个正则表达式和词法能力的解析器,并根据您的建议使用acceptIf。但上面的例子不能按预期工作仍然很奇怪。感谢您的帮助 – awertos

+0

@awertos我终于找出问题所在。第一种解决方案比我想象的更合适 - 我只是改变它,使错误出现在适当的地方,不消耗任何非空间字符。 –