1. 程式人生 > >C++ 程式碼統計工具 & 判斷一行程式碼是否為註釋行

C++ 程式碼統計工具 & 判斷一行程式碼是否為註釋行

這兩天接手了一個專案,專案定義了一種自己語法,所以有了判斷註釋的需求。

這裡自己簡單實現了一個,程式碼非常精簡。

提供的註釋語法和C++是一模一樣的, 允許 // 和 /* */兩種註釋

兩個問題:

1、如何判斷某一行是否為註釋行。

2、如何判斷是否“進入”了註釋段,也就是在/* */中間。

先說第2點,思路:從上往下,一行一行的檢查。

用一個flag標識是否”進入”了註釋,具體在一行當中,遇到/* flag 置1,遇到 */ 置0;這樣即使一行中有多個/* */也不會判斷錯誤。

比如  /*int x*/ printf(); /* int y */ /*int z;  之後

就進入了註釋段了,在遇到*/之前接下里的行都是註釋行。但它本身並不是註釋行。

這就說到第1點了,除了這個以下幾種情況也都是註釋行,如果一行是以//開頭,僅有/*兩個字元 ,僅有*/兩個字元,以/*開頭類似這種的/* xx */ /* x xxx */  //xxx,以/*開頭類似 /* int x 這種的。

很自然的想到遞迴計算:

在一行中,前面部分閉合了就不用管了,把後面的子串繼續遞迴。只要遇到上面說的幾種情況中的一種就說明是註釋行。遞迴結束還沒遇到說明是普通行。

而且在遞迴中也可以更新flag是否進入了註釋段。 兩者可以在同一個函式中進行,非常方便。

判斷一行本身是否為註釋行以及更新/*、*/的函式如下。

bool Counter::judgeAndUpdateComment(string line, bool& flag)  
{
	// /* xxxxxx */ /* x xxx */  //xxxx
	// /*xx */ int x /*
	if(line[0] == '/' && line[1] == '/') return true;
	if(line[0] == '*' && line[1] == '/' && line.length()==2) {flag = false; return true;}
	if(line[0] == '/' && line[1] == '*' && line.length()==2) return flag = true;
	if(line[0] == '/' && line[1] == '*' && line.find("*/")==string::npos) return flag = true;
	string::size_type idx = line.find("/*");
	if(idx != string::npos)   
	{
		flag = true;
	}
	if(flag)
	{
		idx = line.find("*/");
		if(idx != string::npos)
		{
			flag = false;
			line[idx] = line[idx+1] = ' ';
			string sub = line.substr(idx+2,line.length()-idx-2);
			trim(sub);
			if (judgeAndUpdateComment(sub,flag)) return true;
		}
	}
	return false;
}

當然,要配合下面的函式裡呼叫

void Counter::countOneFile(string filepath)
{
	
	ifstream file;
	file.open(filepath,ios::in);
	if (!file.is_open())
	{
		cout << "can't open the file :" << filepath << endl;
		exit(1);
	}
	char buffer[10000];
	bool comment_flag = false;  
	while (!file.eof() )  
    {  
        file.getline(buffer,10000);  
		string line(buffer);
		trim(line);
		if (line.empty())
		{
			m_blank_line++;
		}
		else if(comment_flag)  //如果已經進入了註釋段
		{
			m_comment_line++;
			judgeAndUpdateComment(line,comment_flag); //更新 */
		}
		else if (judgeAndUpdateComment(line,comment_flag)) // 本身是註釋行
		{
			m_comment_line++;
		}
		else
		{
			m_real_line++;
		}
		
    }  
	cout << "finish: " << filepath << endl;
}
 

這裡我沒有考慮雙引號的影響。雙引號裡的東西應該忽略的,但是我沒有考慮,如果出現類似

string str = "abcd /* "; 的程式碼,程式得出的結果是災難性的錯誤。有需要的同學自己加上。