最近我在学习解析表达式语法。在网上搜索了一些关于它的资料后,我终于坐下来弄脏了手。我想用 PEG 实现 Kernighan 和 Pike 的 The Unix Programming Environment 中的 hoc 程序。就此而言,我选择了 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 文件。
感谢和问候桑塔努
# 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'