语法规范解决Shift/Reduce冲突

Jas*_*ban 6 bison context-free-grammar shift-reduce-conflict jison

我正在使用Jison(Bison)来创建一个简单的标记语言.我显然对此很陌生,但略有不同的变化非常好.我只是不明白S/R冲突的根源.

"文本"由两个词法分析器操作(具有不同的"开始条件")返回似乎并不重要,我喜欢这样,因为它似乎允许语法具有更少的规则,并且因为给用户的错误消息是一致的.我已经尝试将"文本"规则放在一起,不管上下文如何,我也尝试给每个标记一个不同的名称,但它似乎对S/R冲突没有任何影响.

解析器是SUPPOSED用于创建具有纯文本,子数组和各种特殊节点的json对象.

规格:

/* lexical grammar */
%lex

%s bracketed

%%

<bracketed>(\\.|[^\\\,\[\]])+       { yytext = yytext.replace(/\\(.)/g, '$1'); return 'Text'; }
<INITIAL>(\\.|[^\\\[])+             { yytext = yytext.replace(/\\(.)/g, '$1'); return 'Text'; }
"["                                 { this.begin('bracketed'); return '['; }
"]"                                 { this.popState(); return ']'; }
","                                 return ','
<<EOF>>                             return 'END'

/lex

%start template

%%    

template
    : sentence END
    ;

sentence
    : /* empty */
    | sentence Text
    | sentence '[' ']'
    | sentence '[' dynamic ']'
    ;

dynamic
    : sentence
    /*| dynamic ',' sentence*/
    ;
Run Code Online (Sandbox Code Playgroud)

警告:

Conflict in grammar: multiple actions possible when lookahead token is ] in state 5
- reduce by rule: sentence ->
- shift token (then go to state 6)

States with conflicts:
State 5
  sentence -> sentence [ .] #lookaheads= END Text [ ]
  sentence -> sentence [ .dynamic ] #lookaheads= END Text [ ]
  dynamic -> .sentence #lookaheads= ]
  sentence -> . #lookaheads= ] Text [
  sentence -> .sentence Text
  sentence -> .sentence [ ]
  sentence -> .sentence [ dynamic ]
Run Code Online (Sandbox Code Playgroud)

不同的生成器算法或多或少有麻烦,但它们似乎都有麻烦.

谢谢!

Chr*_*odd 14

冲突基本上来自这两个规则:

sentence: sentence '[' Text ']'
        | sentence '[' sentenceList ']'
Run Code Online (Sandbox Code Playgroud)

原因是在看到a sentence和a [并查看下一个令牌之后Text,解析器不知道是否移位Text,匹配第一个规则,或者将其Text视为开始sentenceList匹配第二个规则.

现在,如果你有一个使用2令牌前瞻的解析器生成器,这不会有问题,但是野牛是LALR(1)(1是一个令牌前瞻).

您可以尝试以下几种方法:

  • 在词法分析器中做额外的预测以区分Text-follow-by-]和Text-not-follow-by-]作为两个不同的标记,然后重写规则以使用这两个标记.

  • 使用bison的%glr-parser功能来使用GLR解析器.这将以两种方式解析句子,然后丢弃不匹配的句子

  • 重构语法,不需要2令牌前瞻.

在你的情况下有效的一个重构是重写sentence规则,使它们正确递归而不是左递归:

sentence: /* empty */
        | Text sentence 
        | '[' ']' sentence
        | '[' Text ']' sentence
        | '[' sentenceList ']' sentence
        ;
Run Code Online (Sandbox Code Playgroud)

这避免了sentence(或任何其他以sentence诸如此类sentenceList开头的sentence: /*empty*/规则)以规则的空值减少开始.因此,解析器可以Text在有问题的情况下自由地移动减少,直到它看到下一个令牌.但是,它确实具有内存使用含义,因为它会导致解析器基本上将整个输入转移到解析器堆栈,然后一次减少一个句子.

您可以做的另一个重构是将[Text][]构造包含在[sentenceList]:

sentence: /* empty */
        | sentence Text 
        | sentence '[' sentenceList ']'
        ;

sentenceList: sentence
            | sentenceList ',' sentence
Run Code Online (Sandbox Code Playgroud)

所以现在a sentenceList是用逗号分隔的一个或多个句子(而不是两个或更多),并且在sentence '[' sentenceList ']'规则的动作中,你要检查sentenceList它是否是两个或更多的句子并采取适当的行动.