用PEG.js解析完整的数学表达式

时间:2013-10-15 20:07:43

标签: javascript parsing peg pegjs

我正在尝试扩展PEG.js的示例语法,用于解析我的在线BASIC解释器实验的所有4个运算符的数学表达式:

http://www.dantonag.it/basicjs/basicjs.html

但并非所有表达式都被正确解析。

这是我的PEG语法:

expression = additive

additive = left:multiplicative atag:("+" / "-") right:additive { return {tag: atag, left:left, right:right}; } / multiplicative

multiplicative = left:primary atag:("*" / "/") right:multiplicative { return {tag: atag, left:left, right:right}; } / primary

primary = number / "(" additive:additive ")" { return additive; }

number = digits:[0-9]+ { return parseInt(digits.join(""), 10); }

它正确地解析了2 * 3 + 1(给出7)这样的表达式,但没有像2-1-1这样的表达式,它给出了2而不是0。

你能帮我改进和调试吗?

提前致谢。

编辑:我已将“数字”规则添加到语法中。是的,我的语法为输出提供了一个类似于解析树的递归结构。

2 个答案:

答案 0 :(得分:8)

马特的回答是正确的,但关于如何在pegjs中实现左联结:

expression = additive

additive
  = first:multiplicative rest:(("+" / "-") multiplicative)+ {
    return rest.reduce(function(memo, curr) {
      return {atag: curr[0], left: memo, right: curr[1]};
    }, first);
  }
  / multiplicative

multiplicative
  = first:primary rest:(("*" / "/") primary)+ {
    return rest.reduce(function(memo, curr) {
      return {atag: curr[0], left: memo, right: curr[1]};
    }, first);
  }
  / primary

primary
  = number
  / "(" additive:additive ")" { return additive; }

number
  = digits:[0-9]+ { return parseInt(digits.join(""), 10); }

javascript.pegjs示例Matt链接使用类似的方法。关键是处理与列表具有相同优先级的操作字符串,这允许您使用正确的关联性构建树。

答案 1 :(得分:5)

首先:你的语法缺少number规则。另外,正如我确定你知道的那样,在你的例子中运行你的语法(在添加number之后)并没有给出2,而是像解析树一样。您是否介意更新问题以解决这两个问题?


<强>问题: 看起来你已经陷入了联想。当两个具有相同优先级的运算符竞争操作数时,关联性发挥作用。在您的示例中,--竞争 - 显然它将具有与其本身相同的优先级 - 但关联性对于打破+和{{1}之间的联系也很重要} {},以及-*之间。

我假设/被正确解析,因为两个运算符具有不同的优先级,这意味着关联性不起作用,并且您的语法正确地实现了优先级(尽管您应该注意2*3+1是一个更标准的例子,表明乘法的优先级高于加法,因为2+3*1的简单从左到右解析得到与解析器相同的结果。

我假设您希望2*3+1是左关联的,但基于此示例,它在您的语法中似乎是右关联的:

  • 输入:

    -
  • 输出(解析为1-2-3 ):

    1-(2-3)

左关联树看起来像这样(来自{ "tag": "-", "left": "1", "right": { "tag": "-", "left": "2", "right": "3" } } ):

(1-2)-3

您应该注意,您的其他运算符也似乎是右关联而不是左 - 。

解决方案:我真的不知道peg.js是如何运作的,但是有一些快速的谷歌搜索出现this

基于语法的运算符优先级和关联性解决方案通常非常讨厌(请参阅grammar for Python获取证据),因此您可能需要查看[自上而下]运算符优先级解析以获得更灵活和更具表现力的替代方案。 Douglas Crockford,Vaughn Pratt和Annika Aasa都有一些关于这个主题的好文章。