Scala解析器组合器(几乎)琐碎的语法

时间:2012-01-31 06:50:07

标签: parsing scala parser-combinators

我一直在努力为一个(非常)简单的语言创建一个解析器,如下所示:

block{you are a cow too blkA{ but maybe not} and so is he} hear me moo blockZ{moooooo}

我可以使用正则表达式将其分开:

.*?[^ ]*?\\{
.*?\\}

基本上会继续吃字符,直到找到匹配[^ ]*?\\{\\}的字符:块的开头或结尾。我的问题是,如果我想使用Scala的Parser Combinators,我该怎么做?我目前有:

   def expr: Parser[Any] = (block | text)+
   def text = ".+?".r
   def block = "[^ ]*?\\{".r ~ expr ~ "}"

但这不起作用:

parsed: List(b, l, o, c, k, {, y, o, u, a, r, e, a, c, o, w, t, o, o, b, l, k, A, {, b, u, t, m, a, y, b, e, n, o, t, }, a, n, d, s, o, i, s, h, e, }, h, e, a, r, m, e, m, o, o)

似乎block解析器没有触发,因此text解析器被重复触发。但当我删除text解析器时:

   def expr: Parser[Any] = (block)+

我明白了:

failure: string matching regex `[^ ]*?\{' expected but `y' found

block{you are a cow too blkA{ but maybe not} and so is he} hear me moo  
      ^

显然block解析器 工作,除非text解析器存在。发生了什么?为了这么基本的语法,是否有一种“正确”的方式?

编辑:更改了标题,因为仅仅因为解决问题而不再那么不情愿

编辑:我现在有这个:

def expr: Parser[Any] = (block | text)+

def text = "[^\\}]".r

def block = "[^ ]*?\\{".r ~ expr ~ "}"

这背后的逻辑是,对于每个角色,它测试它是否是块的开始。如果不是,则移动到下一个字符。这给了我:

parsed: List(((block{~List(y, o, u, a, r, e, a, c, o, w, t, o, o, ((blkA{~List(b, u, t, m, a, y, b, e, n, o, t))~}), a, n, d, s, o, i, s, h, e))~}), h, e, a, r, m, e, m, o, o)

这是正确的。它虽然逐个解析非块字符,这可能是一个性能问题(我认为?)。有没有办法一次解析所有这些非块字符并将它们留在一个大字符串中?

1 个答案:

答案 0 :(得分:2)

问题是text正在消耗所有结束花括号(})。它是这样的:

expr -> block -> expr -> text.+ (until all input is consumed)

此时,它退出expr并尝试解析不存在的},失败,并在第一个text上回退到expr。< / p>

您可以使用log查看解析时发生的情况。