野牛转移/减少冲突的简单语法

时间:2010-07-30 15:45:35

标签: parsing bison shift-reduce-conflict

我正在为我设计的语言构建解析器,其中类型名称以大写字母开头,变量名称以小写字母开头,这样词法分析器可以区分并提供不同的标记。此外,字符串'this'由词法分析器识别(它是一种OOP语言)并作为单独的标记传递。最后,数据成员只能在'this'对象上访问,所以我建立了语法:

%token TYPENAME
%token VARNAME
%token THIS

%%

start:
    Expression
    ;

Expression:
    THIS
    | THIS '.' VARNAME
    | Expression '.' TYPENAME
    ;
%%

Expression的第一条规则允许用户将'this'作为值传递(例如,从方法返回或传递给方法调用)。第二个是访问'this'的数据。第三个规则是调用方法,但是我删除了括号和参数,因为它们与问题无关。原来的语法显然比这大得多,但是这是产生相同错误的最小部分(1个Shift / Reduce冲突) - 我把它隔离到自己的解析器文件中并验证了这个,所以错误与任何无关其他符号。

据我所知,这里给出的语法是明确的,所以不应该产生任何错误。如果删除三个规则中的任何一个或将第二个规则更改为

Expression '.' VARNAME

没有冲突。在任何情况下,我可能都需要有人说明为什么会发生这种冲突以及如何解决冲突。

2 个答案:

答案 0 :(得分:4)

问题是语法只能提前一个。因此,当您看到THIS然后.时,您是否在第2行(Expression: THIS '.' VARNAME)或第3行(Expression: Expression '.' TYPENAME,通过根据第1行的缩减)。< / p>

语法可以将THIS.缩减为Expression.,然后查找TYPENAME或将其转移到THIS.并查找VARNAME,但它有决定何时到达.

答案 1 :(得分:3)

我尽量避免y.output,但有时它会有所帮助。我查看了它制作的文件并看到了。

state 1

    2 Expression: THIS.  [$end, '.']
    3           | THIS . '.' VARNAME

    '.'  shift, and go to state 4

    '.'       [reduce using rule 2 (Expression)]
    $default  reduce using rule 2 (Expression)

基本上它是说它看到'。'并且可以减少或者可以改变。减少使我有时因为很难被罚款。转变是规则3并且是显而易见的(但输出没有提到规则#)。减少它所看到的''。在这种情况下是行

| Expression '.' TYPENAME

当它转到Expression时,它会查看下一个字母('。')并进入。现在它看到THIS |所以当它到达该语句的末尾时它会预期'。'。当它离开或错误。但它看到了这个'。'而它介于此​​和'。'之间(因此out文件中的点)它可以减少规则,因此存在路径冲突。我相信你可以使用%glr-parser来允许它尝试两者,但是你遇到的冲突越多,你就越有可能获得意外输出或模糊错误。我过去有歧义错误。他们很烦人,特别是如果你不记得什么规则造成或影响他们。建议避免冲突。

在尝试使用野牛之前,我强烈推荐this book

我无法想到一个“伟大的”解决方案,但这不会产生冲突

start:
    ExpressionLoop
    ;

ExpressionLoop:
      Expression
    | ExpressionLoop ';' Expression
    ;
Expression:
      rval 
    | rval '.' TYPENAME
    | THIS //trick is moving this AWAY so it doesnt reduce
rval:

    THIS '.' VARNAME

替代方案,您可以通过向规则添加更多内容来使其减少,因此它不会很快减少,或者通过在之前或之后添加令牌来明确哪条路径采取或失败(请记住,它必须知道减少任何路径之前) )

start:
    ExpressionLoop
    ;

ExpressionLoop:
      Expression
    | ExpressionLoop ';' Expression
    ;
Expression:
      rval 
    | rval '.' TYPENAME
rval:
      THIS '@'
    | THIS '.' VARNAME
%%

-edit-注意如果我想做func paramtype varname我不能因为根据词法分析器func的类型是Var(它是A-Za-z09_)以及类型。 param和varname也都是var,所以这会导致我减少/减少冲突。你不能把它写成它们是什么,只是它们看起来像什么。所以在写作时请记住这一点。你必须编写一个令牌来区分这两个,或者把它写成两个中的一个但是在代码中编写额外的逻辑(在规则右侧的{}中的部分)来检查它是否是一个函数名或一个类型并处理这两种情况。