Bison 减少/减少C样式强制转换操作符中的冲突

Bison 减少/减少C样式强制转换操作符中的冲突,bison,reduce-reduce-conflict,Bison,Reduce Reduce Conflict,我正在为某种查询语言编写bison+flex解析器,需要向其中添加一个C风格的cast操作符。以下是守则的相关部分: %token <characterToken> Identifier %token <commandToken> LRPAR RRPAR %type <characterToken> typename %type <operationValue> generalExp castExp variable %% ge

我正在为某种查询语言编写bison+flex解析器,需要向其中添加一个C风格的cast操作符。以下是守则的相关部分:

%token <characterToken>  Identifier
%token <commandToken>    LRPAR RRPAR

%type <characterToken>   typename
%type <operationValue>   generalExp castExp variable

%%
generalExp: variable
      | LRPAR generalExp RRPAR
       { /* some code here */ }
      | castExp
      ;

castExp: LRPAR typename RRPAR generalExp
   { /* some code here */ }
   ;

variable: Identifier 
    { /* some code here*/ };
typename: Identifier;
%%
可能的解决方案是在相应的lex文件中列出所有有效的类型名(如long、int、char),但是我还需要支持使用过的定义类型

UPD: 另一个解决方案是使用bison GLR解析器,由于性能下降,我不希望使用它

bison-v
输出是。

最佳猜测——语法中未显示的其他部分允许两个连续的
generalExp
,它们之间没有标记。因此,当您有一个像
(Identifier)expression
这样的输入时,它可能是一个强制转换或两个连续的
generalExp
s


处理所有冲突的方法与处理所有冲突的方法相同--使用
-v
选项运行bison,以获得一个
.output
文件,该文件显示所有状态以及哪些状态在哪些符号上有哪些冲突。一旦你知道了这一点,你就有机会知道可以做什么。

是的,
C
cast语法的选择非常糟糕。如果不知道强制转换中的内容是类型还是值,则无法正确解析。以下是C中的一些案例:

(f)*a    // cast the value pointed to by a to type f, or multiply f by a?
(f)(a+b) // cast a+b to type f or call the function f with argument a+b?
我发现处理这个问题的最简单方法是让lexer查询符号表,这样它就可以为typename和标识符返回不同的标记类型。(这正是C语法的工作方式。)在lexer和解析器之间共享符号表有点难看,特别是在允许范围类型定义的情况下,但这是可以做到的。为了正确的词法分析,词法分析人员只需要知道符号是否是类型的名称;您可能不必假设符号不是类型,除非它已显式声明为类型,因此严格来说,不必在使用之前声明所有符号。(例如,在C++中,非类型类成员在使用之前不必声明,并且仍然可以工作。) 说到这里,我强烈建议您认真考虑对强制转换使用不同的语法,如果可能的话。除了对解析器来说是一件痛苦的事情外,它们对人类读者来说也可能是令人烦恼的模棱两可的(参见上面的示例),而且强制转换并不(或者不应该)常见到需要缩写语法的程度

C++风格的强制转换--
cast(value)
--由于将比较运算符循环为括号而产生歧义,但如果使用尖括号的操作是一组固定的关键字,则可以接受。(否则,将创建另一个上下文,lexer需要在其中区分名称类型。)

就我个人而言,特别是对于查询语言,我会选择

value as type


它(IMO)更具可读性,更易于解析,而不会更难键入

我也遇到了类似的问题——违反了以下规则:

expr: expr "+" expr
expr: "(" type ")" expr
我通过设置操作符的优先级来解决这个问题:

%precedence "+"
%precedence ")"

这将优先级设置为“
,因此第二条规则将被优先使用。

冲突状态的
bison-v
输出是什么?冲突消息与关于
typename
的警告相关:当解析器在
标识符之后看到
时,它不知道是将其缩减为
变量
还是
类型名
。这就是减少/减少冲突。它选择通过总是减少到
变量
来解决冲突,因为生成在语法中较早。这使得
typename
无用,因此它会生成警告。然而,我认为这些都不能回答你的问题。我试图分别回答你的问题;如果您愿意,我可以将此注释添加到答案中。不,任何规则都不允许两个连续的generalExp,因此解析器无法尝试处理此类表达式。是的,可能的解决方案之一是为具有有限密钥集的TypeName引入不同的标记,但我需要支持用户定义的类型,在查询范围之外定义的。为cast操作符引入另一种语法可能是最好的解决方案。@apchhee:这就是我建议让lexer访问语法表的原因。如果我有时间,我会修改答案,提供一个我所说的例子。让lexer访问语法表是有效的,非常感谢你的答案!
expr: expr "+" expr
expr: "(" type ")" expr
%precedence "+"
%precedence ")"