Parsing 为什么我的EOF/linebreak非终端总是有shift/reduce冲突?

Parsing 为什么我的EOF/linebreak非终端总是有shift/reduce冲突?,parsing,ocaml,shift-reduce-conflict,menhir,Parsing,Ocaml,Shift Reduce Conflict,Menhir,所以,我在语法分析方面还处于初级阶段。我需要帮助剖析Menhir报告的冲突,当我需要减少冲突时 以这个小语法为例: (* {2 Tokens } *) %token EOF %token COLON PIPE SEMICOLON %token <string> COUNT %token <string> IDENTIFIER %start <AST.t> script %start <AST.statement> statement %% (*

所以,我在语法分析方面还处于初级阶段。我需要帮助剖析Menhir报告的冲突,当我需要减少冲突时

以这个小语法为例:

(* {2 Tokens } *)
%token EOF
%token COLON PIPE SEMICOLON
%token <string> COUNT
%token <string> IDENTIFIER

%start <AST.t> script
%start <AST.statement> statement

%%
(* {2 Rules } *)

script:
 | it = separated_list(break, statement); break?; EOF { { statements = it } }
 ;

statement:
 | COLON*; count = COUNT?; cmd = command { AST.make_statement ~count ~cmd }
 ;

command:
 | it = IDENTIFIER { it }
 ;

break:
 | SEMICOLON { }
 ;

%%

我花了一个晚上的时间试图通过文档挖掘出转换/减少冲突实际上是什么,但我不得不承认,我很难理解我所阅读的内容。有人能给我一个简单(好的,尽可能多)的解释转移/减少冲突吗?具体使用上述示例的上下文?

问题在于,在查看分号时,解析器无法确定它应该使用EOF还是列表的其余部分。原因是您使用了
break
作为可选的终止符,而不是分隔符

我建议你改变你的主要规则:

script:
 | it = optterm_list(break, statement); EOF { { statements = it } }
 ;
然后自己定义
opterm_列表
combinator,如下所示:

optterm_list(separator, X):
  | separator? {[]}
  | l=optterm_nonempty_list(separator, X) { l } 
optterm_nonempty_list(separator, X):
  | x = X separator? { [ x ] }
  | x = X
    separator
    xs = optterm_nonempty_list(separator, X)
     { x :: xs }
optterm_list(separator, X):
  | separator? {[]}
  | l=optterm_nonempty_list(separator, X) { l } 
optterm_nonempty_list(separator, X):
  | x = X separator? { [ x ] }
  | x = X
    separator
    xs = optterm_nonempty_list(separator, X)
     { x :: xs }