Bison 野牛转移/减少和减少/减少冲突

Bison 野牛转移/减少和减少/减少冲突,bison,shift-reduce-conflict,reduce-reduce-conflict,Bison,Shift Reduce Conflict,Reduce Reduce Conflict,好的,我已经试着重写了三次野牛语法,并且不断遇到shift/reduce和reduce/reduce冲突。我试图解析的语法如下。{…}中的项用于其中一个。[…]中的项目是可选的 CONSTANT constant-name constant-class constant-class = { EQUALS expression numeric-options } { EQUALS STRING string string-options }

好的,我已经试着重写了三次野牛语法,并且不断遇到shift/reduce和reduce/reduce冲突。我试图解析的语法如下。{…}中的项用于其中一个。[…]中的项目是可选的

CONSTANT constant-name constant-class 
    constant-class = { EQUALS expression numeric-options } 
                     { EQUALS STRING string string-options } 
    numeric-options = [ PREFIX prefix-string ] 
                      [ TAG tag-string ]  
                      [ COUNTER #local-name ]
                      [ TYPENAME type-name ] ; 
    string-options = [ PREFIX prefix-string ] 
                     [ TAG tag-string ] ; 

CONSTANT (constant-name,...) EQUALS expression 
                 [ INCREMENT expression ] 
                 [ PREFIX prefix-string ] 
                 [ TAG tag-string ] 
                 [ COUNTER #local-name ] 
                 [ TYPENAME type-name ]; 

CONSTANT  constant-name EQUALS expression, 
                . 
                . 
                . 
 ;

CONSTANT  (constant-name,...) EQUALS expression, 
                . 
                . 
                . 
 ; 
我对让最后三个都工作有意见。我可以让其中任何一个工作,但不是全部4个。我现在有一个班次/减少和一个减少/减少冲突。我掌握的语法如下:

constant
    : SDL_K_CONSTANT constant_style ';'
    ;

constant_style
    : constant_name constant_class
    | constant_list
    | constant_set
    ;

constant_name
    : sdl_name
    ;

constant_class
    : SDL_K_EQUALS sdl_decimal
    | SDL_K_EQUALS SDL_K_STRING sdl_string
    ;

constant_names
    : constant_name
    | constant_names ',' constant_name
    | '(' constant_names ')'
    ;

names_equal
    : constant_names SDL_K_EQUALS sdl_decimal
    ;

constant_list
    : names_equal
    ;

constant_set
    : names_equal
    | constant_set ',' names_equal
    ;
我认为这些名称是自我记录的(至少你应该能够理解类型)。任何帮助都将不胜感激。我有一种感觉,我要么简化得太多,要么不够

注意:我知道了如何编辑我的帖子,删除了选项,并将SDL_K_逗号和SDL_K_SEMI改为“,”和“;”,分别

谢谢

下面是一些应该分析的示例:

CONSTANT block_node_size EQUALS 24;
CONSTANT Strcon EQUALS STRING "This is a string constant" PREFIX Jg$ 
#block_size = 24;
CONSTANT block_node_size EQUALS #block_size;
CONSTANT 
    xyz EQUALS 10, 
    alpha EQUALS 0, 
    noname EQUALS 63;
CONSTANT
    (zyx, nameless) EQUALS 10,
    (beta) EQUALS 1,
    gamma EQUALS 42;
CONSTANT ( 
    bits, 
    bytes, 
    words, 
    longs, 
    quads, 
    octas 
    ) EQUALS 0 INCREMENT 1 PREFIX ctx$;
CONSTANT 
    (bad_block,bad_data,,,, 
    overlay,rewrite) EQUALS 0 INCREMENT 4;
CONSTANT (pli,c,bliss,macro) 
    EQUALS 4 INCREMENT 4 PREFIX lang$ 
    COUNTER #lang;
CONSTANT (basic,pascal,fortran) 
    EQUALS #lang + 4 INCREMENT 4 PREFIX lang$;
我希望这有帮助

顺便说一句:这里是EBNF(排序)用于:

/*
 * Define the CONSTANT construct (Left out Expression).
 */
Str                 ::= "\"" Printable* "\""
Name                ::= "$" | "_" | [A-Za-z] ("$" | "_" | [A-Z0-9a-z])*
Names               ::= Name | ("(" Name ("," Name )* ")")
Constant_class      ::= "EQUALS" (Expression Numeric_options | "STRING" Str 
                        String_options)
String_options      ::= Prefix? Tag?
Numeric_options     ::= String_options Counter? Typename? Radix?
Increment_options   ::= Increment? Numeric_options
Constant_list       ::= Names "EQUALS" Expression Increment_options
Constant_set        ::= Names Equals Expression
                        ("," Names "EQUALS" Expression)*
Constant            ::= "CONSTANT" (Name Constant_class | Constant_list | 
                        Constant_set) ";"?
Prefix              ::= "PREFIX" Str
Tag                 ::= "TAG" Str
Radix               ::= "RADIX" ("DEC" | "OCT" | "HEX")
Counter             ::= "COUNTER" Variable
Increment           ::= "INCREMENT" Expression
Typename            ::= "TYPENAME" Name

我想就是这样。

我有点难以理解您实际上在做什么,所以我做了一些假设,并在下面提供了一些备选方案。我希望它能接近

基本问题是语法规范中的歧义。其中一个可能是错误的:根据您的模板,
EQUAL
的左侧似乎是单个
name
或由括号包围的逗号分隔的
name
列表。但是,您的语法允许使用逗号分隔的
名称列表
s,列表中的第一项(或唯一一项)可能是括号内的名称列表:

constant_names
    : constant_name
    | constant_names ',' constant_name
    | '(' constant_names ')
这将匹配
a
a,b
(a,b)
(a,b),c
(a,b),c,d
。但我认为只有第一个和第三个是真正有意的

在任何情况下,您都有两个产品:

constant_style
    : constant_name constant_class
    | constant_list
关于第一个问题,我们有:

constant_class
    : SDL_K_EQUALS sdl_decimal
constant_list: names_equal
names_equal
    : constant_names SDL_K_EQUALS sdl_decimal
第二,我们有:

constant_class
    : SDL_K_EQUALS sdl_decimal
constant_list: names_equal
names_equal
    : constant_names SDL_K_EQUALS sdl_decimal
由于
constant\u name
可以匹配单个
名称
,因此有两种不同的方法匹配
answer=42
,这将不可避免地导致解析冲突

但是对于
answer=42
,还有另一种可能的解析:

constant_set
    : names_equal
所以,让我们从简化所有这些东西开始,然后我们也许可以回到你最初的目标。其思想是将所有语法相似的东西都考虑在内:

constant-stmt  : "CONSTANT" clause-list ';'
clause-list    : clause | clause-list ',' clause
clause         : left-hand-side "EQUALS" right-hand-side
left-hand-side : name | '(' name-list ')'
name-list      : name | name-list ',' name
right-hand-side: expression   /* See below */
我希望这一切都足够简单易懂

但我们可以从原文中看到(至少在某些情况下),
右侧的选项比上面的代码片段中的选项多得多。只需将其他语法添加到
右侧
,就很简单了。然而,其意图似乎是,这些额外选项仅在存在单一条款的情况下可用。在这种情况下,我们可以这样做:

constant-stmt  : "CONSTANT" constant-body ';'
constant-body  : complex-clause | clause-list
clause-list    : clause | clause-list ',' clause
clause         : left-hand-side "EQUALS" right-hand-side
right-hand-side: expression
complex-clause : left-hand-side "EQUALS" complex-rhs
complex-rhs    : expression numeric-options
               | "STRING" string-literal string-options
但不幸的是,这又变得模棱两可,因为
数值选项
可能为空,因此
表达式
将同时匹配
右侧
复杂右侧

在实践中,这种模糊性并不重要。声明
name EQUALS expression
作为
常量
声明中的唯一声明或作为此类声明列表中的一个声明,在语义上没有区别。因此,一种可能是忽略由此产生的reduce/reduce冲突,可能是将
%expect 1
放入文件中。但这真的不是很愉快。因此,我们将努力消除这个问题

一种方法是坚持第一个
复杂rhs
至少有一个
数值选项
。但那真的很烦人。首先,我们必须创建另一个子句类型--
First complex子句
或类似的类型--其次,我们必须写出至少存在一个选项的要求

作为一个更简单的选择,我们可以要求一个
子句列表
至少有两个
子句
s,而不是只有一个。由于每个
子句
也可以匹配
复杂子句
,因此对
子句列表
的限制不会拒绝任何有效的
子句
。这给了我们一个很小的变化:

constant-body  : complex-clause | clause-list
clause-list    : clause ',' clause | clause-list ',' clause

补遗 通过对预期语法的更精确描述(尽管它仍然缺少一些细节),我修改了上面的语法,试图解析完整的语言。基本原则保持不变:定义由单个
复杂子句
(包括简单子句的大小写)或至少两个简单
子句
组成。唯一的区别是两种子句类型的定义方式

我还修复了名称列表生成,因此可以省略单个名称(例如,
(坏块、坏数据、、、覆盖、重写)
)。如指南所示,列表必须至少包含一个名称,这会使语法稍微复杂化

我添加了指南中的选项(但不是EBNF中的额外选项)。我没有尝试处理省略的分号,虽然有一个声明没有尾随分号的示例,但指南中似乎不允许省略分号。(那可能是一个打字错误。)据我所知,我添加了
表达式的定义

我还添加了本地名称分配语句,因为它位于测试文件中,而且很容易

语法如下:

definition      : %empty
                | definition constant-defn
                | definition local-assign
local-assign    : LOCAL_NAME '=' expression ';'
constant-defn   : "CONSTANT" constant-body ';'
constant-body   : complex-clause | clause-list
clause-list     : clause ',' clause | clause-list ',' clause
clause          : name "EQUALS" expression
                | name-list "EQUALS" expression
complex-clause  : name "EQUALS" expression numeric-options
                | name-list "EQUALS" expression list-options
                | name "EQUALS" "STRING" string-literal string-options
                | name-list "EQUALS" "STRING" string-literal string-options
name-list       : '(' names ')'
names           : optional-commas name | names ',' name | names ','
optional-commas : %empty | optional-commas ',' 
string-options  : prefix-option tag-option
numeric-options : string-options counter-option typename-option
list-options    : increment-option numeric-options
increment-option: %empty | "INCREMENT" expression
prefix-option   : %empty | "PREFIX" prefix-name
tag-option      : %empty | "TAG" tag-name
counter-option  : %empty | "COUNTER" LOCAL_NAME
typename-option : %empty | "TYPENAME" name

expression      : '-' expression %prec UNOP
                | expression '*' expression
                | expression '/' expression
                | expression '+' expression
                | expression '-' expression
                | expression '@' expression
                | expression '&' expression
                | expression '!' expression
                | '(' expression ')'
                | INTEGER
                | IDENT
                | LOCAL_NAME
name            : IDENT | QUOTED_IDENT
prefix-name     : IDENT | QUOTED_NULL | QUOTED_IDENT
tag-name        : IDENT | QUOTED_NULL | QUOTED_IDENT | QUOTED_TAG
string-literal  : QUOTED_NULL | QUOTED_IDENT | QUOTED_TAG | QUOTED_STRING
您将看到,我添加了对各种类型的引用字符串的区分,以便能够处理(大多数)引用字符串可能出现的不同上下文。正如指南中所指出的,我没有将最多4个字符的带引号的字符串用作整数常量,因为我没有及时注意到这一点,也因为我无法通过简短的阅读了解其意图是否正确