c++ - LBNF、C函数声明/定义、reduce减少冲突

标签 c++ c context-free-grammar bnf bnfc

我试图在 LBNF 中表示 C/C++ 函数声明具有以下(近似)形式(<sym> 表示可选性,[rule] 是一个零或多个列表):

type ident ( [type <id>] );

虽然函数定义具有以下形式:

type ident ( [type id] ) { [stmt] }

目前,我有以下 LBNF:

entrypoints Program ;
Program.   Program ::= [TopDef] ;

FnDef.     TopDef ::= Type Ident "(" [Arg] ")" Block ;
FnDecl.    TopDef ::= Type Ident "(" [Par] ")" ";" ;
separator nonempty TopDef "" ;

Param.     Par ::= Type ;
NParam.    Par ::= Type Ident ;
separator Par "," ;

Arg.       Arg ::= Type Ident;
separator  Arg "," ;

-- Types ---------------------------------------------------

Int.       Type ::= "int" ;
--- more types...
separator  Type "," ;

这会按预期导致减少/减少冲突。 有没有办法在解析器/词法分析器中解决这个问题?

我可以用下面的语法解决它:

FnDef.     TopDef ::= Type Ident "(" [Arg] ")" Block ;
FnDecl.    TopDef ::= Type Ident "(" [Arg] ")" ";" ;
separator nonempty TopDef "" ;

Arg.       Arg ::= Type Ident;
Arg.       Arg ::= Type;
separator  Arg "," ;

然后在类型检查器中检查函数定义是否具有每个参数的标识符,但这感觉不太令人满意......

这在 C 等语言中通常是如何处理的?

最佳答案

您提到您认为不满意的方式实际上是通常完成的方式。

但是您可以生成一个精确的 LALR(1) 文法。这是一个完整的没有冲突的野牛规范:

%token TYPE ID
%%
prog       : 
           | prog decl ';'
decl       : TYPE ID def_list block
           | TYPE ID def_list ';'
           | TYPE ID dec_list ';'
block      : '{' prog '}'
def_list   : '(' ')'
           | '(' type_ids ')'
dec_list   : '(' type_opt_ids ')'
type_opt_id: type_only
           | type_id
type_ids   : type_id
           | type_ids ',' type_id
type_opt_ids
           : type_only
           | type_ids ',' type_only  /* SEE BELOW */
           | type_opt_ids ',' type_opt_id
type_id    : TYPE ID
type_only  : TYPE        

关键是要避免强制解析器做出决定。当它传递参数列表时,它可以继续减少 type_opt_ids,只要它不命中匿名参数即可。如果它命中一个,它会减少 type_ids 并继续处理其余参数,无论它们是否是匿名的。最后,定义只允许 type_ids 但声明(明确地)接受其中任何一个。

要实现这一点,type_idtype_only 的语义类型需要相同,因为 type_ids type_opt_ids 必须是该类型的列表。否则,您需要在标记为 /* SEE BELOW */

的生产中将 type_ids 转换为 type_opt_ids

(很抱歉没有将其转换为您的形式主义,但我想用 bison 对其进行测试以验证它实际上没有冲突。转换应该很容易。)


请注意,C++ 很乐意允许没有参数名称的函数定义,但 C 不是。另一方面,C 允许没有类型的函数定义,或者在参数名称列表和函数体之间使用类型声明。但这是一个附带问题,真的。

关于c++ - LBNF、C函数声明/定义、reduce减少冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37058622/

相关文章:

c++ - boost::asio::socket keep alive set_option 异常

c++ - 如何在不写入任何内容的情况下获得 stringstream 的实际最大大小?

c++ - 防止选项卡控件的上下控制?

grammar - 所有字符串 X2Y,其中 X 和 Y 由 0 和 1 组成,且 X ≠ Y

compiler-construction - 如何在上下文无关文法中判断运算符的优先级

C++ 从另一个类访问私有(private)结构

c++ - 设置二进制函数以使用转换时出现问题

c - Memcpy 导致 strcpy 中出现段错误?包括 Valgrind 输出

c - 使用 proc 文件系统将信息从 LKM 写入用户空间

compiler-construction - 如何找到递归语法的FIRST和FOLLOW集?