2012-09-09 58 views
1

我的任務是創建ANTLR語法,分析C#源代碼文件並生成類層次結構。然後,我將使用它來生成類圖。ANTLR規則跳過方法體

我寫了規則來解析命名空間,類聲明和方法聲明。現在我遇到了跳過方法體的問題。我不需要解析它們,因爲在我的任務中屍體是無用的。

我寫了簡單的規則:

body: 
'{' .* '}' 
; 

,但它不能正常工作,當方法是這樣的:

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

規則第一支柱什麼是好的匹配,那麼它匹配

... 
{ 
    ... 

as'any'(。*),然後第三個大括號作爲最後的大括號,什麼是不好的,規則結束。

任何人都可以幫助我爲方法體編寫適當的規則嗎?正如我之前所說,我不想解析它們 - 只是跳過。

UPDATE:

這裏強烈基於ADAM12我的問題的解決方案回答

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

你是一個非常艱鉅的任務,你將不得不接受身體內的對{和},和您還必須忽略正文中的註釋和字符串內容。像「[{」這樣的字符串在生成小部分json或/ *時非常常見(如果(...){某些代碼被臨時刪除,它們會干擾您的規則。 – Casperah

+0

@Casperah,你能否給我舉一些例子如何接受對{}?我認爲我應該在這裏使用遞歸,但沒有更多 – GrzegorzM

回答

1

你必須使用匹配圓括號對遞歸規則。

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

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

此代碼假定您在此處使用解析器,因此字符串和註釋已被排除。 ANTLR不允許否定解析器規則中的多個備選方案,所以上面的代碼依賴於按順序嘗試備選方案的事實。它應該給出一個警告,即備選方案1和2都匹配'(',因此選擇第一個備選方案,這就是我們想要的。

0

您可以處理詞法分析器中(嵌套)塊的遞歸。讓你的班級定義也包括開放{,這樣就不會讓這個遞歸的詞法分析規則吞噬整個班級的內容了。

一個毫無疑問不是完整的快速演示,而是一個體面的開始「模糊解析/ 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'))* '"' 
; 

我運行生成的pa對下列Java源文件RSER:

/* 
    ... 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' 
Method   'm1' 
ClassDecl  'Inner' 
Method   'm2'