peg / leg - 用于表达式解析的PEG规范的一些奇怪行为

时间:2014-05-31 03:59:10

标签: regex parsing expression grammar peg

最近我正在学习解析表达式语法。通过搜索网页阅读了一些材料,我终于坐下来弄脏了手。我想过用Kernighan和Pike用Unix实现Unix编程环境中的特殊程序。就此而言,我选择了PEG解析器生成器peg/leg,因为它具有良好的文档和大量示例。我将示例中的dc.peg作为我的起点,并在phoc版本1中实现了对一元减号的支持。

现在当我为一元减去写下面的作品时,生成的解析器无法识别((-9)),(( - 9)* 3)/ 4,(8 - ( - 2)* 5)/ 2- (2 + 2)等。

Operand     <-    SGNValue
                  / Value
SGNValue    <-    OPEN? '-' Value CLOSE?
Value       <-    NUMBER                                     
                  / OPEN Sum CLOSE

但是,如果我将SGNValue更改为以下表达式,则表达式完全匹配。

SGNValue    <-    '-' NUMBER                                        
                  / '-' OPEN Sum CLOSE

请问有人在这里向我解释上述制作规则有什么问题吗?

我也在用这篇文章附上phoc1.peg文件。

谢谢和问候 Santanu

# Grammar

Expr        <-    SPACE Sum EOL                                      { printf("%f\n", pop()); }
                  / (!(EOL / 'q') .)* EOL                            { printf("error: quiting hoc1\n"); \
                                                                   exit(1); }
                  / 'q' EOL                                          { printf("bye\n"); exit(0);}

Sum         <-    Product ( PLUS  Product                            { double r = pop(), l = pop(); \
                                                                   push(l + r); }
                  / MINUS Product                                    { double r = pop(), l = pop(); \
                                                                   push(l - r); }
                  )*

Product     <-    Operand ( TIMES  Operand                           { double r = pop(), l = pop(); \
                                                                   push(l * r); }
                  / DIVIDE Operand                                   { double r = pop(), l = pop(); \
                                                                   push(l / r); }
                  )*

Operand     <-    SGNValue
                  / Value

## SGNValue    <-    OPEN? '-' Value CLOSE?
## This production rule was throwing error
## for expressions like ((-9)), ((-9)*3)/4,
## (8-(-2)*5)/2-(2+2), etc. probably due to
## left recurssion. But it was behaving as expected
## for (((9))), ((9)*2), etc.

SGNValue    <-    '-' NUMBER                                         { push(-1*atof(yytext)); }
                  / '-' OPEN Sum CLOSE                               { double d = pop(); push(-1*d); }

Value       <-    NUMBER                                             { push(atof(yytext)); }
                  / OPEN Sum CLOSE

# Lexemes

NUMBER  <-  < [0-9]+ ('.' [0-9]+)? >  SPACE
PLUS    <-  '+'                       SPACE
MINUS   <-  '-'                       SPACE
TIMES   <-  '*'                       SPACE
DIVIDE  <-  '/'                       SPACE
OPEN    <-  '('                       SPACE
CLOSE   <-  ')'                       SPACE
SPACE   <-  [ \t]*
EOL     <-  '\n' / '\r\n' / '\r'

1 个答案:

答案 0 :(得分:3)

当你写:

SGNValue    <-    OPEN? '-' Value CLOSE?

您说OPENCLOSE都是可选的,这意味着其中一个或两个都可能存在。例如,它会很乐意匹配-9),其中只缺少OPEN

所以前缀((-9VALUE <- OPEN Sum CLOSE匹配,(-9SUM匹配,OPERAND递归VALUE / SGNValue,匹配VALUE;请记住,PEG的 / 运算符是订单感知的,因此它首先尝试再次匹配(的{​​{1}}并进行递归。然后我们-9VALUE无法匹配,但它肯定与SGNValue匹配。不幸的是,-9)匹配SGNValue,如上所述,之后没有足够的近括号来匹配来自两个VALUE的待处理的开括号。

我不是PEG的忠实粉丝,订单感知交替是其中一个原因。但这是一个非常个人化的观点;如果他们为你工作,对你更有力量。 OPEN? Sum CLOSE?在任何BNF风格的语法形式中都是不正确的,但通常它会导致接受错误的句子而不是拒绝正确的句子。