2011-02-06 55 views
3

我需要计算正确的C#源文件中的类的数量。 我写了下面的语法:计算班级计数的部分语法

grammar CSharpClassGrammar; 

options 
{ 
     language=CSharp2; 

} 

@parser::namespace { CSharpClassGrammar.Generated } 
@lexer::namespace { CSharpClassGrammar.Generated } 

@header 
{ 
     using System; 
     using System.Collections.Generic; 

} 

@members 
{ 
     private List<string> _classCollector = new List<string>(); 
     public List<string> ClassCollector { get { return 
_classCollector; } } 

} 

/*------------------------------------------------------------------ 
* PARSER RULES 
*------------------------------------------------------------------*/ 

csfile : class_declaration* EOF 
     ; 

class_declaration 
     : (ACCESSLEVEL | MODIFIERS)* PARTIAL? 'class' CLASSNAME 
      class_body 
      ';'? 
      { _classCollector.Add($CLASSNAME.text); } 
     ; 

class_body 
     : '{' class_declaration* '}' 
     ; 

/*------------------------------------------------------------------ 
* LEXER RULES 
*------------------------------------------------------------------*/ 

ACCESSLEVEL 
     : 'public' | 'internal' | 'protected' | 'private' | 'protected 
internal' 
     ; 

MODIFIERS 
     : 'static' | 'sealed' | 'abstract' 
     ; 

PARTIAL 
     : 'partial' 
     ; 

CLASSNAME 
     : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* 
     ; 

COMMENT 
     : '//' ~('\n'|'\r')* {$channel=HIDDEN;} 
     | '/*' (options {greedy=false;} : .)* '*/' {$channel=HIDDEN;} 
     ; 

WHITESPACE 
     : ('\t' | ' ' | '\r' | '\n'| '\u000C')+ { $channel = HIDDEN; } 
     ; 

这个解析器正确计算空类(和嵌套类太)空类体:

internal class DeclarationClass1 
{ 
    class DeclarationClass2 
    { 
     public class DeclarationClass3 
     { 
      abstract class DeclarationClass4 
      { 
      } 
     } 
    } 
} 

我需要计算与非空体类,例如作为:

class TestClass 
{ 
    int a = 42; 

    class Nested { } 
} 

我需要以某种方式忽略所有“不是类声明”的代码。 在上例中忽略

int a = 42; 

我该怎么做?可能是其他语言的例子吗?
请帮忙!

+1

请注意部分班级;请注意,部分类可以在一个文件中多次,一次只在一个文件中,或者分散在多个文件中。 Assembly.GetTypes()不是一个选项吗? – 2011-02-06 15:11:10

+0

谢谢,我记得部分课程。 Assembly.GetTypes()不适合我,我需要在源代码级别处理这个。 – 2011-02-06 15:14:08

回答

3

当您只对源文件的某些部分感兴趣时,可以在选项{012}}中设置filter=true部分。{...}部分。这将使您只能定义您感兴趣的那些标记,而您没有定义的标记被词法分析器忽略。

请注意,这只适用于词法分析器语法,不适用于组合(或解析器)语法。

小演示:['X', 'class', 'Foo']

lexer grammar CSharpClassLexer; 

options { 
    language=CSharp2; 
    filter=true; 
} 

@namespace { Demo } 

Comment 
    : '//' ~('\r' | '\n')* 
    | '/*' .* '*/' 
    ; 

String 
    : '"' ('\\' . | ~('"' | '\\' | '\r' | '\n'))* '"' 
    | '@' '"' ('"' '"' | ~'"')* '"' 
    ; 

Class 
    : 'class' Space+ Identifier 
    {Console.WriteLine("Found class: " + $Identifier.text);} 
    ; 

Space 
    : ' ' | '\t' | '\r' | '\n' 
    ; 

Identifier 
    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* 
    ; 

你离开Identifier在那里,因为你不希望Xclass Foo被符号化的做到这一点是非常重要的。随着Identifier在那里,Xclass将成为整个标识符。

using System; 
using Antlr.Runtime; 

namespace Demo 
{ 
    class MainClass 
    { 
     public static void Main (string[] args) 
     { 
      string source = 
@"class TestClass 
{ 
    int a = 42; 

    string _class = ""inside a string literal: class FooBar {}...""; 

    class Nested { 
     /* class NotAClass {} */ 

     // class X { } 

     class DoubleNested { 
      string str = @"" 
       multi line string 
       class Bar {} 
      ""; 
     } 
    } 
}"; 
      Console.WriteLine("source=\n" + source + "\n-------------------------"); 
      ANTLRStringStream Input = new ANTLRStringStream(source); 
      CSharpClassLexer Lexer = new CSharpClassLexer(Input); 
      CommonTokenStream Tokens = new CommonTokenStream(Lexer); 
      Tokens.GetTokens(); 
     } 
    } 
} 

产生以下输出:

语法可以用下面的类进行测试

source= 
class TestClass 
{ 
    int a = 42; 

    string _class = "inside a string literal: class FooBar {}..."; 

    class Nested { 
     /* class NotAClass {} */ 

     // class X { } 

     class DoubleNested { 
      string str = @" 
       multi line string 
       class Bar {} 
      "; 
     } 
    } 
} 
------------------------- 
Found class: TestClass 
Found class: Nested 
Found class: DoubleNested 

注意,这仅仅是一个快速演示,我不知道如果我处理在语法中正确的字符串文字(我不熟悉C#),但这个演示应该给你一个开始。

祝你好运!