解析算术/布尔表达式但跳过捕获

时间:2014-10-01 21:10:37

标签: haskell parsec

给出以下表达式

x = a + 3 + b * 5

我想在下面的数据结构中写一下,我只想捕获RHS上使用的变量并保持字符串不变。解析更具体的结构没有意义,因为我正在进行从语言到语言的转换,而不是处理评估

Variable "x" (Expr ["a","b"] "a + 3 + b * 5")

我一直在使用this tutorial作为我的起点,但我不确定如何在没有buildExpressionParser的情况下编写表达式解析器。这似乎不是我应该这样做的方式。

1 个答案:

答案 0 :(得分:1)

我不确定你为什么要避免使用buildExpressionParser,因为它隐藏了使用中缀运算符解析表达式的大量复杂性。这是正确做事的方式....

对此感到抱歉,但是现在我已经解决了这个问题,我可以回答你的问题。

首先,这是一些背景 -

使用中缀运算符为表达式编写解析器的主要原因是运算符优先级。你想确保这个

x+y*z

解析为

  +
 / \
x   *
    /\  
   y  z

而不是这个

    *
   / \
  +   z
 / \
x   y

选择正确的parsetree并不是一个非常难以解决的问题....但如果你不注意,你可以编写一些非常糟糕的代码。为什么?性能....

忽略优先级的可能的分析树的数量随着输入的大小呈指数增长。例如,如果你编写代码来尝试所有可能性,那么除了那些具有适当优先级的代码之外,当你的解析器处理现实世界中的任何东西时,你会有一个令人讨厌的惊喜(记住,指数复杂性通常只是因为慢,它基本上不是一个解决方案....你可能会发现你正在等待半个小时进行简单的解析,没有人会使用该解析器。)

我不会重复"正确"的详细信息。这里的解决方案(谷歌搜索将提供详细信息),除了注意正确的解决方案在输入的大小O(n)运行,并且buildExpressionParser隐藏了为您编写这样的解析器的所有复杂性。


所以,回到原来的问题......

您是否需要使用buildExpressionParser将变量从RHS中取出,还是有更好的方法?

你不需要它......

由于您所关心的只是获取右侧使用的变量,因此您并不关心运算符优先级。您可以将所有内容保持关联,并编写一个简单的O(n)解析器。 parsetrees将是错误的,但是谁在乎呢?你仍然会得到相同的变量。你甚至不需要一个无上下文的语法,这个正则表达基本上就是这样做

<variable>(<operator><variable>)*

(其中<variable><operator>以明显的方式定义。)

然而....

我不推荐这样做,因为尽管它很简单,但它仍然比使用buildExpressionParser更有效。扩展(比如添加括号)会更棘手。但最重要的是,稍后,您可能会意外地将它用于需要完整分析树的地方,并且混淆了一段时间为什么运算符优先级如此完全混乱。

另一个解决方案是,你可以重写你的语法以消除歧义(再次,谷歌将告诉你如何)....这将是一个很好的学习练习,但你基本上会重复buildExpressionParser在内部做什么。