Bison 如何解决这一S/R冲突

Bison 如何解决这一S/R冲突,bison,lr,shift-reduce-conflict,jison,Bison,Lr,Shift Reduce Conflict,Jison,以下是我的工作EBNF语法的简化: %token NEWLINE BLOCK_MARK A %start file file: block+ NEWLINE*; block: BLOCK_MARK line; line: A+; \n和EOF都将换行符吐出作为标记(这样,在EOF之前不需要一个结束换行符)。它与以下流一起工作: BLOCK_MARK A A BLOCK_MARK A NEWLINE[actually EOF] 现在我想在一个块中有几个行,至少一个是必需的,其余的用换行符隔开

以下是我的工作EBNF语法的简化:

%token NEWLINE BLOCK_MARK A
%start file

file: block+ NEWLINE*;
block: BLOCK_MARK line;
line: A+;
\n和EOF都将换行符吐出作为标记(这样,在EOF之前不需要一个结束换行符)。它与以下流一起工作:

BLOCK_MARK A A BLOCK_MARK A NEWLINE[actually EOF]
现在我想在一个
块中有几个
,至少一个是必需的,其余的用
换行符
隔开。例如:

BLOCK_MARK A A NEWLINE A A BLOCK_MARK A A A EOF
我试着这样做:

file: block+ NEWLINE*;
block: BLOCK_MARK line moreline*;
line: A+;
moreline: NEWLINE line;
但Jison抱怨说,当“向前看”为“换行”时,S/R冲突。我猜状态机在决定
换行符
是新块
的一部分还是
文件
中的最后一个
换行符*
时会感到困惑(这是必需的,因为文件可以以换行符/EOF结尾)


如何修复此问题?

您想要的是使换行成为前一行的一部分,将除换行以外的任何内容的缩减推迟到看到换行之后。因此,你最终会:

file: block+ ;
block: BLOCK_MARK line_nl+ line_nonl? | BLOCK_MARK line_nonl ;
line_nl: line NEWLINE ;
line_nonl: line ;
line: A+ ;

现在,上面的唯一问题是它不允许任何空行(空行将是语法错误)。但这和你原来的语法是一样的。

基于克里斯·多德的想法,但与我第一次尝试时的想法相反。基本的想法是删除
文件
中的
换行符*
,毕竟
中已经包含了这一点

file: block+;
block: BLOCK_MARK line_nonl line_nl* NEWLINE?;
line_nl: NEWLINE line_nonl;
line_nonl: A+;

我认为这个解决了所有的问题。

一种机制可能是停止将换行符视为EOF;他们根本不是一回事。我对它的工作原理感到非常困惑。@JonathanLeffler相反,我将EOF视为新线。我想我不是唯一一个这样做的人,使结束换行符不需要(因为EOF也被解析为换行符)。将
file
更改为
file:block+NEWLINE*EOF
并不能解决问题,而且会使问题变得更糟,需要
NEWLINE
(对于
line
)和
EOF
(对于
file
)作为最后解析的令牌。我认为这是有意义的,谢谢!我得到了一个空白的线覆盖在扫描仪(\n+SPITE新行)。Woops,没有解决整个问题,因为这对原来的用例失败了(我想我已经遇到了这个问题)。代码>块\标记块\标记EOF失败,但只有在至少有两行存在时才需要换行!与
BLOCK\u标记一个换行符一个BLOCK\u标记一个EOF
,它工作得很好(因为
换行符
中至少有一个
换行符或EOF
)。添加了一个附加规则:
BLOCK:BLOCK\u标记行符应该可以解决这个问题。我的语法稍微复杂一些,我不得不添加一个额外的产品来涵盖这两种情况,但这解决了问题。我在你的基础上提出了另一个解决方案,看起来也不错(另一个答案),不过我会接受(可能会使用)你的。