2011-02-06 2 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; } 
     ; 

이 파서가 제대로 (너무 중첩 클래스) 빈 클래스를 계산 빈 클래스 몸 : I가 비어 있지 몸 클래스를 계산해야하는

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

같은 나는 다음과 같은 문법을 썼다 다음과 같이 :

class TestClass 
{ 
    int a = 42; 

    class Nested { } 
} 

"클래스 선언이 아님"모든 코드를 무시해야합니다. 위 예의 경우 무시하십시오.

int a = 42; 

어떻게하면됩니까? 다른 언어의 예가 될 수 있습니까?
제발, 도와주세요!

+1

부분 수업도주의하십시오. 부분 클래스는 한 파일에서 여러 번, 한 파일에서 한 번만 또는 여러 파일에 걸쳐 여러 번 나타날 수 있습니다. Assembly.GetTypes()는 옵션이 아닙니다. –

+0

감사합니다. 부분 수업에 대해서 기억합니다. Assembly.GetTypes()는 저에게 적합하지 않습니다. 소스 레벨에서 이것을 처리해야합니다. –

답변

3

소스 파일의 특정 부분에만 관심이있는 경우 옵션 섹션에 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')* 
    ; 

그것은 당신이 Xclass Foo 같이 토큰 화되고 싶지 않기 때문에 당신이 거기에 Identifier을 남겨 중요합니다. 여기에 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#에 익숙하지 않습니다). 그러나이 데모는 여러분에게 시작을 제공 할 것입니다.

행운을 빈다.

+0

@Ben, 아마도 C#에 익숙하지 않다는 나의 말을 놓쳤을 것입니다. 그리고 제가 게시 한 것은 질문을 시작하는 데 필요한 간단한 데모 일뿐입니다. –

+0

좋아요, 대신 질문 자체에 대해 말씀 드리겠습니다. –

+0

@Ben, 여기에 남겨두면 아무런 문제가 없습니다. (맹목적으로 내 예를 사용하는 사람을위한 경고로) 나는 당신이 언급 한 "이상한"사례를 설명하기 위해 내 게시물을 편집하지 않을 것이라는 점을 지적하고있었습니다. :) –