0

我试图在 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 这样的语言中是如何处理的?

4

1 回答 1

2

你提到你觉得不满意的方式实际上是它通常完成的方式。

但是您可以生成精确的 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只要它没有碰到匿名参数,它就可以不断减少 a。如果它达到一个,它会减少 atype_ids并继续其余参数,无论它们是否是匿名的。最后,定义只允许,type_ids但声明(明确)接受。

为了实现这一点, and 的语义类型type_id需要type_only相同,因为type_idsand都type_opt_ids必须是该类型的列表。否则,您需要在生产中转换type_idstype_opt_ids/* SEE BELOW */

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


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

于 2016-05-05T22:30:19.130 回答