2010-01-18 61 views
3

我有一個用C#編寫的程序,當給定C++或C#文件時,計算文件中的行數,計算註釋中和設計器中的行數 - 生成的代碼塊。我想添加計算文件中有多少個函數以及這些函數有多少行的功能。我無法弄清楚如何確定一行(或一系列行)是否是函數(或方法)的開始。在行計數程序中識別C#或C++函數

至少,函數聲明是返回類型,後跟標識符和參數列表。有沒有辦法在C#中確定一個令牌是一個有效的返回類型?如果沒有,有什麼方法可以輕鬆確定一行代碼是否是函數的開始?基本上我需要能夠可靠地區分類似的東西。

bool isThere() 
{ 
... 
} 

bool isHere = isThere() 

和從

isThere() 

以及任何其他函數聲明真人秀。

回答

1

從掃描範圍開始。當您在文件中工作時,您需要計算開放大括號{和近距離大括號},以便您知道您所處的範圍。在掃描文件時還需要解析//和/ * ... */,所以你可以知道什麼時候發生了什麼,而不是真正的代碼。還有#if,但你必須編譯代碼才能知道如何解釋這些。

然後,你需要解析文本之前立即打開一些範圍的大括號來找出它們是什麼。您的函數可能位於全局作用域,類作用域或命名空間作用域中,因此您必須能夠解析命名空間和類來識別您正在查看的作用域類型。你通常可以用相當簡單的解析方法逃脫(大多數程序員使用類似的風格 - 例如,有人在'Fred類'和它的開放大括號之間插入空行是不常見的,但他們可能會寫'class Fred {'。也是他們會把額外的垃圾放在線上的機會 - 例如'模板類__DECLSPEC MYWEIRDMACRO Fred {'。但是,你可以用一個非常簡單的方法逃脫「這行是否包含'class'這個詞,兩邊都有空格?啓發式,將在大多數情況下工作。

好了,現在你知道你是一個namepace裏面,一個類的內部,你會發現一個新的開放範圍。它是一個方法?

主要識別一種方法的特點是:

  • 返回類型。這可以是任何字符序列,可以是許多標記(「__DLLEXPORT const unsigned myInt32typedef * &」)。除非你編譯整個項目,否則你沒有機會。
  • 函數名稱。一個令牌(但要注意「運營商=」等)
  • 一對括號中包含零個或多個參數或「空白」。這是你最好的線索。
  • 函數聲明不會包含某些保留字,這些保留字將位於許多範圍之前(例如枚舉,類,結構等)。它可能會使用一些保留字(模板,常量等),您不能絆倒。

因此,你可以搜索一個空行,或結束在; {或}表示前面的語句/作用域的結尾。然後抓住該點和你的示波器的大括號之間的所有文本。然後提取一個令牌列表,並嘗試匹配參數列表括號。檢查這些標記是否爲保留字(枚舉,結構,類等)。

這會給你一個「合理程度的信心」,你有一個方法。你不需要太多的解析來獲得相當高的準確性。你可能會花很多時間去查找所有混淆了你的「解析器」的特殊情況,但是如果你正在研究一個合理的一致的代碼庫(也就是你自己公司的代碼),那麼你可能會識別出所有的代碼中的方法相當容易。

-1

有沒有辦法在C#中確定令牌是有效的返回類型?

您可以很容易地確定它是返回類型還是錯誤(通過確保它不是其他任何可能位於該位置的東西)。而且你可能不需要保證無效代碼上的「正確」行爲。

然後你看看括號。

+0

爲什麼downvote? – 2010-01-18 21:38:57

+0

這不是我,但可能是因爲「在那個位置沒有其他任何東西」涵蓋了幾千種不同的東西,在很多情況下,你將不得不解析相當多的周圍代碼來解決它。你怎麼知道「MyThing」是否是返回類型?例如它可能是一個擴展爲「類Thing {」的宏。你怎麼知道你找到的返回類型是否不在評論中? – 2010-01-18 22:18:46

2

這樣做的問題是要準確地做到這一點,您必須考慮到可以定義C#函數的所有可能方式。本質上,你需要編寫一個解析器。這樣做超出了簡單的答案範圍。

將有可能很多答案對這個問題的正則表達式的形式,他們將努力在通常情況下,但可能會炸燬在角落情況下,像下面

int 
? 
/* this 
is */ 
main /* legal */ (code c) { 
} 
+0

請記住,C++很難解析,儘管我認爲C#好得多。 – 2010-01-18 21:52:39

+2

@David,C#很難解析,C++幾乎是不可能的:) – JaredPar 2010-01-18 21:54:47

+0

你稱之爲角落案例?這很簡單:-)但是你是對的,很難單獨解析C++/C#代碼片段。但是,如果你使用一些簡單的啓發式方法,它比你想象的要容易得多。最大的挑戰在於處理範圍和註釋,因爲它們可以遠離方法聲明開始數千行,並且註釋可以包含代碼。 C#實際上比C++更難,因​​爲你可以使用更多的標記(*&?^ <>,partial等),並且你也可以在聲明的前面添加屬性。泛型和模板使事情更有趣。 – 2010-01-18 22:13:33

1

我可能會使用一個正則表達式,儘管給定了數據類型和聲明選項的數量以及用戶定義的類型/類型,但這並不重要。爲了簡單地避免函數調用捕獲作業,則可能是正則表達式(未經測試),如啓動:

(private|public|internal|protected|virtual)?\s+(static)?\s+(int|bool|string|byte|char|double|long)\s+([A-Za-z][A-Za-z_0-9]*)\s*\(

這不(由一個長鏡頭)趕上一切,你需要調整它。

另一種方法可能涉及反射來確定函數聲明,但是當您想要執行靜態源代碼分析時,這可能不合適。

0

如果你想寫一個真正的解析器(我知道你可能不想),然後嘗試ANTLR。如果沒有別的,它將是一個有趣的項目