【问题标题】:Why do I always have a shift/reduce conflict with my EOF / linebreak nonterminals?为什么我的 EOF / linebreak 非终结符总是发生 shift/reduce 冲突?
【发布时间】:2018-11-06 01:57:08
【问题描述】:

所以,在整理语法分析方面,我还很初级。当我遇到减班冲突时,我需要帮助剖析 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 { }
 ;

%%

Menhir 的--explain 标志生成了对由此产生的移位/减少冲突的描述。不幸的是,我无法确定它的正面或反面:

** Conflict (shift/reduce) in state 3.
** Token involved: SEMICOLON
** This state is reached from script after reading:

statement 

** The derivations that appear below have the following common factor:
** (The question mark symbol (?) represents the spot where the derivations begin to differ.)

script 
(?)

** In state 3, looking ahead at SEMICOLON, shifting is permitted
** because of the following sub-derivation:

loption(separated_nonempty_list(break,statement)) option(break) EOF 
separated_nonempty_list(break,statement) 
statement break separated_nonempty_list(break,statement) 
          . SEMICOLON 

** In state 3, looking ahead at SEMICOLON, reducing production
** separated_nonempty_list(break,statement) -> statement 
** is permitted because of the following sub-derivation:

loption(separated_nonempty_list(break,statement)) option(break) EOF // lookahead token appears because option(break) can begin with SEMICOLON
separated_nonempty_list(break,statement) // lookahead token is inherited
statement . 

我整晚都在试图深入研究什么是 shift/reduce 冲突的文档,但我不得不承认我很难理解我的意思正在看书。有人可以给我一个关于移位/减少冲突的简单(好吧,尽可能多地)解释吗?具体使用上例的上下文?

【问题讨论】:

    标签: parsing ocaml shift-reduce-conflict menhir


    【解决方案1】:

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

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

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

    然后自己定义 optterm_list 组合器,如下所示:

    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 }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多