使用Peg.js解析布尔表达式时的歧义语法

时间:2015-03-16 19:53:36

标签: javascript peg

我正在编写一个从布尔表达式生成抽象语法树的解析器。

我有以下Peg.js语法支持^,分别为&|

start
  = operation

// optional whitespace
_  = [ \t\r\n]*

operation "operation"
  = "("? _ left:(operand / operation) _ operator:operator _ right:(operand / operation) _  ")"?
  {
    return {
      operation: operator,
      between: [ left, right ]
    };
  }

operator "operator"
  = operator:["&"|"|"]  
  {
    return operator;
  }

operand "operand"
  = operand:[a-z]
  { 
    return { operand: operand };
  }

它成功解析了a & ba & (b | c)之类的表达式,但是如果表达式以操作开头则失败:

(a | b) & c
Line 1, column 8: Expected end of input but " " found.

如果用括号括起来,表达式会被正确解析:

((a | b) & c)

我的猜测是Peg.js仅将(a | b)作为操作,而不是父操作的操作数,因此在看到& c时失败。

我错过了什么?

1 个答案:

答案 0 :(得分:5)

您的操作规则表示括号是可选的,但有一个不强制另一个在那里。例如,(a & b被成功解析。

您需要将其分解为更小的部分。 andor的单独规则是允许操作符优先执行其操作。

试试这个:

start
  = sentence

sentence
  = orSentence

orSentence
  = lhs:andSentence __ '|' __ rhs:orSentence { return { operation: '|', between: [lhs, rhs] }; }
  / andSentence

andSentence
  = lhs:primarySentence __ '&' __ rhs:andSentence { return { operation: '&', between: [lhs, rhs] }; }
  / primarySentence

primarySentence
  = '(' _ sentence:sentence _ ')' { return sentence; }
  / operand

operand
  = operand:[a-z] { return { operand: operand }; }

_ "optionalWhiteSpace"
  = whiteSpace *

__ "mandatoryWhiteSpace"
  = whiteSpace +

whiteSpace
  = [ \t\n\r]+