最近我正在学习解析表达式语法。通过搜索网页阅读了一些材料,我终于坐下来弄脏了手。我想过用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'
答案 0 :(得分:3)
当你写:
SGNValue <- OPEN? '-' Value CLOSE?
您说OPEN
和CLOSE
都是可选的,这意味着其中一个或两个都可能存在。例如,它会很乐意匹配-9)
,其中只缺少OPEN
。
所以前缀((-9
与VALUE <- OPEN Sum CLOSE
匹配,(-9
与SUM
匹配,OPERAND
递归VALUE / SGNValue
,匹配VALUE
;请记住,PEG的 / 运算符是订单感知的,因此它首先尝试再次匹配(
的{{1}}并进行递归。然后我们-9
与VALUE
无法匹配,但它肯定与SGNValue
匹配。不幸的是,-9)
匹配SGNValue
,如上所述,之后没有足够的近括号来匹配来自两个VALUE
的待处理的开括号。
我不是PEG的忠实粉丝,订单感知交替是其中一个原因。但这是一个非常个人化的观点;如果他们为你工作,对你更有力量。 OPEN? Sum CLOSE?
在任何BNF风格的语法形式中都是不正确的,但通常它会导致接受错误的句子而不是拒绝正确的句子。