2012-04-12 96 views
2

如果前视标记是给定值,是否有方法可以指定Bison规则不应该匹配?野牛拿起C函数指针作为函数调用?

我公司目前有以下野牛语法(简体):

var_decl: 
     type ident 
     { 
      $$ = new NVariableDeclaration(*$1, *$2); 
     } | 
     type ident ASSIGN_EQUAL expr 
     { 
      $$ = new NVariableDeclaration(*$1, *$2, $4); 
     } | 
     type CURVED_OPEN STAR ident CURVED_CLOSE CURVED_OPEN func_decl_args CURVED_CLOSE 
     { 
      $$ = new NVariableDeclaration(*(new NFunctionPointerType(*$1, *$7)) /* TODO: free this memory */, *$4); 
     } | 
     type CURVED_OPEN STAR ident CURVED_CLOSE CURVED_OPEN func_decl_args CURVED_CLOSE ASSIGN_EQUAL expr 
     { 
      $$ = new NVariableDeclaration(*(new NFunctionPointerType(*$1, *$7)) /* TODO: free this memory */, *$4, $10); 
     } ; 

... 

deref: 
     STAR ident 
     { 
      $$ = new NDereferenceOperator(*$<ident>2); 
     } | 

... 

type: 
     ident 
     { 
      $$ = new NType($<type>1->name, 0, false); 
      delete $1; 
     } | 
     ... ; 

... 

expr: 
     deref 
     { 
      $$ = $1; 
     } | 
     ... 
     ident 
     { 
      $<ident>$ = $1; 
     } | 
     ... 
     ident CURVED_OPEN call_args CURVED_CLOSE 
     { 
      $$ = new NMethodCall(*$1, *$3); 
      delete $3; 
     } | 
     ... 
     CURVED_OPEN expr CURVED_CLOSE 
     { 
      $$ = $2; 
     } ; 

... 

call_args: 
     /* empty */ 
     { 
      $$ = new ExpressionList(); 
     } | 
     expr 
     { 
      $$ = new ExpressionList(); 
      $$->push_back($1); 
     } | 
     call_args COMMA expr 
     { 
      $1->push_back($3); 
     } ; 

的问题是,在解析时:

void (*ident)(char* some_arg); 

它看到无效(* IDENT),并推断出它必须是一个函数调用而不是函数声明。 有没有一种方法可以告诉Bison它应该有利于展望匹配var_decl而不是将* ident和void减少为derefs和exprs?

+0

你没有讲完整个故事。在你的语法中,表达式不能以类型开始。它是如何从表达式开始的? – 2012-04-12 21:35:18

+0

我已经添加了'type'的语法;正如你所看到的,任何标识符都可以是一个类型。我没有发布整个语法的原因是它的长度为520行,可能会吓跑人们:P – 2012-04-12 21:48:47

+1

您可能需要查看C++的“最烦人的分析”。在那里有一条规则,如果某件事可以成为一种声明,那就是这样。 – 2012-04-12 22:00:38

回答

3

任何标识符可以是类型

这正是这个问题。类似C语言的LALR(1)语法(或类型为C类语法的语言)需要在令牌级别区分类型和其他标识符。也就是说,你需要IDENT和TYPEIDENT是两个不同的标记。 (您必须将有关标识符的数据从编译器反馈回标记器)。这是消除模糊语法的最标准方法。

更新例如参见this ANSI C grammar for Yacc

+0

谢谢!事后看来,实际上让安静有点意义,它必须这样做:) – 2012-04-12 22:35:09