Bison 减少/减少C样式强制转换操作符中的冲突
我正在为某种查询语言编写bison+flex解析器,需要向其中添加一个C风格的cast操作符。以下是守则的相关部分: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
%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 ")"