[英]ambiguous or conflict in LL1 grammar for a shell in C
我正在为执行 shell 实现的项目实现 LL(1) 解析器。 我一直在尝试解决语法中的冲突:
Parsing mode: LL(1).
Grammar:
1. COMMAND_LINE -> COMPLETE_COMMAND PIPED_CMD
2. PIPED_CMD -> PIPE COMPLETE_COMMAND PIPED_CMD
3. | ε
4. COMPLETE_COMMAND -> CMD_PREFIX CMD CMD_SUFFIX
5. CMD_PREFIX -> REDIRECTION CMD_PREFIX
6. | ε
7. CMD_SUFFIX -> REDIRECTION CMD_SUFFIX
8. | CMD_ARG CMD_SUFFIX
9. | ε
10. REDIRECTION -> REDIRECTION_OP WORD
11. | ε
12. CMD -> WORD
13. CMD_ARG -> WORD CMD_ARG
14. | SINGLE_QUOTE WORD DOUBLE_QUOTE CMD_ARG
15. | DOUBLE_QUOTE WORD DOUBLE_QUOTE CMD_ARG
16. | ε
17. REDIRECTION_OP -> HERE_DOC
18. | APPEND
19. | INFILE
20. | OUTFILE
我使用 syntax-cli 检查我的语法,而 ll(1) 解析器是一个自制的实现,如果需要我可以链接我的解析器实现。 syntax-cli 检测到的冲突是:
管道 | 单词 | 单引号 | 双引号 | HERE_DOC | 附加 | 输入文件 | 外档 | $ | |
---|---|---|---|---|---|---|---|---|---|
CMD_SUFFIX | 9 | 7/8 | 7/8 | 7/8 | 7/8 | 7/8 | 7/8 | 7/8 | 9 |
重定向 | 11 | 11 | 11 | 11 | 10/11 | 10/11 | 10/11 | 10/11 | 11 |
命令参数 | 16 | 13/16 | 14/16 | 15/16 | 16 | 16 | 16 | 16 | 16 |
我也试过这个语法:
COMMAND_LINE
: COMPLETE_COMMAND PIPED_CMD
;
PIPED_CMD
: PIPE COMPLETE_COMMAND PIPED_CMD
|
;
COMPLETE_COMMAND
: REDIRECTION CMD REDIRECTION CMD_ARG REDIRECTION
;
REDIRECTION
: REDIRECTION_OP WORD
|
;
CMD
: WORD
;
CMD_ARG
: WORD REDIRECTION CMD_ARG
| SINGLE_QUOTE WORD DOUBLE_QUOTE REDIRECTION CMD_ARG
| DOUBLE_QUOTE WORD DOUBLE_QUOTE REDIRECTION CMD_ARG
| REDIRECTION
;
REDIRECTION_OP
: HERE_DOC
| APPEND
| INFILE
| OUTFILE
;
但是解析器在使用多个重定向时不起作用......
如果没有代表您的更多规范,则无法确保拥有全部。 但事实上,这个语法是有歧义的。
要构建 LL(1) 分析器,您必须能够说出,对于分析器堆栈上的符号的任意组合(符号是终端或非终端尚未读取)和输入缓冲区中的任何单词,应该采用什么规则申请。
将自己置于代码以WORD
开头的情况(这是输入缓冲区中的第一件事)
您首先尝试分析COMMAND_LINE
如果输入缓冲区以WORD
开头,那么只有一个规则可以导致COMMAND_LINE
,即规则COMPLETE_COMMAND PIPED_CMD
(无论如何,无论输入什么,只有这条规则。要么我们可以应用它,要么它是语法错误。但现在, 没有理由引发语法错误,此规则与以WORD
开头的规则兼容)。
所以,现在,在你的堆栈上你有COMPLETE_COMMAND PIPED_CMD
,并且在输入缓冲区中,仍然是相同的WORD
。
堆栈顶部唯一可能的规则是COMPLETE_COMMAND -> CMD_PREFIX CMD CMD_SUFFIX
所以,现在,在你的堆栈上你有CMD_PREFIX CMD CMD_SUFFIX PIPED_CMD
。
并在输入缓冲区WORD
中等待
可以从CMD_PREFIX
应用 2 条规则:
CMD_PREFIX -> REDIRECTION CMD_PREFIX
或CMD_PREFIX -> ε
他们都不能以WORD
开头。 所以要么我们说我们这里有一个空的CMD_PREFIX
(后面是一个以WORD
开头的CMD
)
或者我们可以将其视为后跟空前缀的REDIRECTION
。 REDIRECTION
可以是REDIRECTION -> ε
所以在这一点上两者都是可能的。 要么我们有一个CMD_PREFIX(ε)
要么我们有一个CMD_PREFIX(REDIRECTION(ε), ε)
(或者更多的递归)。
对于要成为 LL(1) 的文法,我们不应该更深入地决定。 从这一点来看,只要知道下一个词位是WORD
,我们也应该能够在其中进行选择。 我们不是。
(事实上 ,即使使用 LL(1) 以外的其他语法,我们也无法决定)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.