【问题标题】:ANTLR rule to skip method bodyANTLR 规则跳过方法体
【发布时间】:2012-09-02 12:21:23
【问题描述】:

我的任务是创建 ANTLR 语法,分析 C# 源代码文件并生成类层次结构。然后,我将使用它来生成类图。

我编写了解析命名空间、类声明和方法声明的规则。现在我有跳过方法体的问题。我不需要解析它们,因为身体在我的任务中毫无用处。

我写了简单的规则:

body:
'{' .* '}'
;

但它不能正常工作,当方法看起来像:

void foo()
{
  ...
  {
    ...
  }
  ...
}

规则匹配第一个大括号没问题,然后匹配

... 
{
  ...

as 'any'(.*) 然后第三个大括号作为最后一个大括号,什么不合适,规则结束。

任何人都可以帮助我为方法体编写适当的规则吗?正如我之前所说,我不想解析它们 - 只是跳过。

更新:

这是我的问题的解决方案,强烈基于 Adam12 的回答

body:
'{' ( ~('{' | '}') | body)* '}'
;

【问题讨论】:

  • 您将面临一项非常艰巨的任务您必须在正文中接受 { 和 } 对,并且您还必须忽略正文中的 cmets 和 string-content。在生成一小部分 json 或 /* if (...) { something*/ 对于一些临时删除的代码时,像“[{”这样的字符串非常常见,它们会扰乱你的规则。
  • @Casperah,你能给我一些例子如何接受成对的 { } 吗?我认为我应该在这里使用递归,仅此而已

标签: c# antlr rule skip


【解决方案1】:

您必须使用匹配括号对的递归规则。

rule1 : '(' 
  (
    nestedParan
  | (~')')*
  )
  ')';

nestedParan : '('
  (
    nestedParan
  | (~')')*
  )
  ')';

此代码假定您在此处使用解析器,因此字符串和 cmets 已被排除在外。 ANTLR 不允许在解析器规则中否定多个备选方案,因此上面的代码依赖于按顺序尝试备选方案的事实。它应该给出一个警告,即选项 1 和 2 都匹配 '(' 并因此选择第一个选项,这就是我们想要的。

【讨论】:

    【解决方案2】:

    您可以在词法分析器中处理(嵌套)块的递归。诀窍是让你的类定义也包括开头的{,这样递归词法分析器规则就不会吞噬类的全部内容。

    一个快速演示,毫无疑问是不完整的,但它是“模糊解析/lex”Java(或稍作修改的 C#)源文件的一个不错的开始:

    grammar T;
    
    parse
     : (t=. {System.out.printf("\%-15s '\%s'\n", tokenNames[$t.type], $t.text.replace("\n", "\\n"));})* EOF
     ;
    
    Skip
     : (StringLiteral | CharLiteral | Comment) {skip();}
     ;
    
    PackageDecl
     : 'package' Spaces Ids {setText($Ids.text);}
     ;
    
    ClassDecl
     : 'class' Spaces Id Spaces? '{' {setText($Id.text);}
     ;
    
    Method
     : Id Spaces? ('(' {setText($Id.text);}
                  | /* no method after all! */ {skip();}
                  )
     ;
    
    MethodOrStaticBlock
     : Block {skip();}
     ;
    
    Any
     : . {skip();}
     ;
    
    // fragments
    fragment Spaces 
     : (' ' | '\t' | '\r' | '\n')+
     ;
    
    fragment Ids
     : Id ('.' Id)*
     ;
    
    fragment Id 
     : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
     ;
    
    fragment Block
     : '{' ( ~('{' | '}' | '"' | '\'' | '/')
           | {input.LA(2) != '/'}?=> '/'
           | StringLiteral
           | CharLiteral
           | Comment
           | Block
           )*
       '}'
     ;
    
    fragment Comment
     : '/*' .* '*/'
     | '//' ~('\r' | '\n')*
     ;
    
    fragment CharLiteral
     : '\'' ('\\\'' | ~('\\' | '\'' | '\r' | '\n'))+ '\''
     ;
    
    fragment StringLiteral
     : '"' ('\\"' | ~('\\' | '"' | '\r' | '\n'))* '"'
     ;
    

    我针对以下 Java 源文件运行生成的解析器:

    /*
        ... package NO.PACKAGE; ...
    */
    package foo.bar;
    
    public final class Mu {
    
      static String x;
    
      static {
        x = "class NotAClass!";
      }
    
      void m1() {
        // {
        while(true) {
          double a = 2.0 / 2;
          if(a == 1.0) { break; } // }
          /* } */
        }
      }
    
      static class Inner {
        int m2   () {return 42; /*comment}*/ }
      }
    }
    

    产生以下输出:

    PackageDecl 'foo.bar'
    ClassDecl 'Mu'
    方法'm1'
    ClassDecl '内部'
    方法'm2'

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-17
      • 1970-01-01
      • 2013-06-09
      • 1970-01-01
      • 1970-01-01
      • 2014-07-24
      • 1970-01-01
      相关资源
      最近更新 更多