【问题标题】:Parse::RecDescent : Parsing nested arithmetic expression?Parse::RecDescent :解析嵌套算术表达式?
【发布时间】:2016-02-14 20:19:19
【问题描述】:

目前我用它来解析算术表达式:

expr  : '(' expr ')' 
      | number op expr 
      | variable op expr 
      | number
      | variable
      | <error>

它适用于简单的表达式,但不能处理嵌套的括号表达式。 知道如何扩展/修改它以便它可以处理嵌套表达式。

例如这有效:

5 + 12
33 - $var
13 + 2 * $v
( 44 + 98 )

但这不起作用:

( 44 + 98 ) / 2
( 44 + 98 ) / ( 5 + $var2 )
( 11 + 5 ) * ( 3 + ( $v * 2 ) )

【问题讨论】:

标签: perl parsing expression parse-recdescent


【解决方案1】:

您的优先链有问题。 1 + (2 + 3) 可以解析为number op expr,右边的expr'(' expr ')',但(1 + 2) + 3 不能,因为expr 不能出现在op 的左边。当然你不能直接添加它,因为左递归是被禁止的。您需要做的就是将其分解为:

expr: term '+' expr
    | term '-' expr
    | term

term: factor '*' term
      | factor '/' term
      | factor

factor: '(' expr ')'
    | number
    | variable
    | <error>

是的,括号一直在链的末端,这可能看起来很奇怪,但它说的是带括号的表达式可以出现在因子可以出现的任何地方,并且会在它冒泡之前被评估。现在很容易看出,由于所有内容都引用factor,因此带括号的表达式可以出现在它需要的任何位置。

【讨论】:

  • 除了以下表达式外似乎有效:# got: 'z / 13 + 22' # expected: 'z / 13 + 22 * abc + 16' 有什么想法吗?
  • @user1019129 抱歉,我已经有一段时间没有这样做了,我忘了允许关联性。已编辑,再试一次?
  • @user1019129 很酷。查看leftop(和rightop)的文档,了解如何进一步简化它——我给你的是规范版本,但它不是P::RD可以做的最好的:)
  • 我已经尝试解决左递归问题几个晚上了,这是我在任何地方看到的最清晰的问题分解!也很容易转移。
  • @kevlarr 很高兴能帮上忙 :)
【解决方案2】:

添加规则以使用中缀运算符将括号表达式与另一个表达式组合:

| '(' expr ')' op expr

顺便说一句,原来的语法没有嵌套表达式,而是以括号中的术语开头的中缀表达式。

一般来说,用户 hobbs 的解决方案是处理具有不同偏好的中缀运算符的表达式的标准方法。它的另一个优点是正确的子表达式求值顺序由语法本身处理,不需要额外的代码处理。

仅当您不需要一个成熟的表达式评估器时才使用我的解决方案(您肯定会发现您需要一个......)。

【讨论】:

  • “只使用这个解决方案......” - 你指的是你的答案还是爱好?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
相关资源
最近更新 更多