LBNF,C函数声明/定义,减少冲突

LBNF, C function declaration / definition, reduce reduce conflict

本文关键字:冲突 定义 声明 函数 LBNF      更新时间:2023-10-16

我试图在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 "," ;

这会按预期减少/减少冲突。有没有一种方法可以在解析器/lexer中解决这个问题?

我可以用以下语法来解决它:

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_idstype_opt_ids都必须是该类型的列表。否则,您需要在标有/* SEE BELOW */ 的产品中将type_ids转换为type_opt_ids

(我很抱歉没有把它转换成你的形式主义,但我想用野牛测试它,以验证它实际上是没有冲突的。转换应该足够容易。)


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