示例#1
0
/*!
* Counts the number of comment lines, removes comments, and
* replaces quoted strings by special chars, e.g., $
* All arguments are modified by the method.
* Special processing for """ and ''' which can be multi-line literal
*  or a multi-line comment if it stands alone.
*
* \param fmap list of processed file lines
* \param result counter results
* \param fmapBak list of original file lines (same as fmap except it contains unmodified quoted strings)
*
* \return method status
*/
int CPythonCounter::CountCommentsSLOC(filemap* fmap, results* result, filemap *fmapBak)
{
	if (BlockCommentStart.empty() && LineCommentStart.empty())
		return 0;
	if (classtype == UNKNOWN || classtype == DATAFILE)
		return 0;

	bool contd = false;
	bool contd_nextline;
	int comment_type = 0;
	/*
	comment_type:
	0 : not a comment
	1 : line comment, whole line
	2 : line comment, embedded
	3 : block comment, undecided
	4 : block comment, embedded
	*/

	size_t idx_start, idx_end, comment_start;
	size_t quote_idx_start;
	string curBlckCmtStart, curBlckCmtEnd, tmp;
	string CurrentQuoteEnd = "";
	bool quote_contd = false;
	filemap::iterator itfmBak = fmapBak->begin();

	quote_idx_start = 0;

	for (filemap::iterator iter = fmap->begin(); iter != fmap->end(); iter++, itfmBak++)
	{
		contd_nextline = false;

		quote_idx_start = 0;
		idx_start = 0;

		if (CUtil::CheckBlank(iter->line))
			continue;
		if (quote_contd)
		{
			// Replace quote until next character
			ReplaceQuote(iter->line, quote_idx_start, quote_contd, CurrentQuoteEnd);
			if (quote_contd)
				continue;
		}

		if (contd)
			comment_type = 3;

		while (!contd_nextline && idx_start < iter->line.length())
		{
			// need to handle multiple quote chars in some languages, both " and ' may be accepted
			quote_idx_start = FindQuote(iter->line, QuoteStart, quote_idx_start, QuoteEscapeFront);
			comment_start = idx_start;
			if (!contd)
			{
				FindCommentStart(iter->line, comment_start, comment_type, curBlckCmtStart, curBlckCmtEnd);
				if (comment_start != string::npos && comment_type > 2)
				{
					// python: check whether this is a multi-line literal or a block comment
					tmp = CUtil::TrimString(iter->line, -1);
					if (iter->line.length() - tmp.length() != comment_start)
					{
						quote_idx_start = comment_start;
						comment_start = string::npos;
					}
				}
			}

			if (comment_start == string::npos && quote_idx_start == string::npos)
				break;

			if (comment_start != string::npos)
				idx_start = comment_start;

			// if found quote before comment, e.g., "this is quote");//comment
			if (quote_idx_start != string::npos && (comment_start == string::npos || quote_idx_start < comment_start))
			{
				ReplaceQuote(iter->line, quote_idx_start, quote_contd, CurrentQuoteEnd);
				if (quote_idx_start > idx_start && quote_idx_start != iter->line.length())
				{
					// comment delimiter inside quote
					idx_start = quote_idx_start;
					continue;
				}
			}
			else if (comment_start != string::npos)
			{
				// comment delimiter starts first
				switch (comment_type)
				{
				case 1:	// line comment, definitely whole line
					iter->line = "";
					itfmBak->line = "";
					result->comment_lines++;
					contd_nextline = true;
					break;
				case 2:	// line comment, possibly embedded
					iter->line = iter->line.substr(0, idx_start);
					itfmBak->line = itfmBak->line.substr(0, idx_start);
					// trim trailing space
					iter->line = CUtil::TrimString(iter->line, 1);
					itfmBak->line = CUtil::TrimString(itfmBak->line, 1);
					if (iter->line.empty())
						result->comment_lines++;	// whole line
					else
						result->e_comm_lines++;		// embedded
					contd_nextline = true;
					break;
				case 3:	// block comment
				case 4:
					if (contd)
						idx_end = iter->line.find(curBlckCmtEnd);
					else
						idx_end = iter->line.find(curBlckCmtEnd, idx_start + curBlckCmtStart.length());

					if (idx_end == string::npos)
					{
						if (comment_type == 3)
						{
							iter->line = "";
							itfmBak->line = "";
							result->comment_lines++;
						}
						else if (comment_type == 4)
						{
							iter->line = iter->line.substr(0, idx_start);
							itfmBak->line = itfmBak->line.substr(0, idx_start);
							// trim trailing space
							iter->line = CUtil::TrimString(iter->line, 1);
							itfmBak->line = CUtil::TrimString(itfmBak->line, 1);
							if (iter->line.empty())
								result->comment_lines++;	// whole line
							else
								result->e_comm_lines++;		// embedded
						}
						contd = true;
						contd_nextline = true;
						break;
					}
					else
					{
						contd = false;
						iter->line.erase(idx_start, idx_end - idx_start + curBlckCmtEnd.length());
						itfmBak->line.erase(idx_start, idx_end - idx_start + curBlckCmtEnd.length());
						if (iter->line.empty())
							result->comment_lines++;
						else
						{
							// trim trailing space
							iter->line = CUtil::TrimString(iter->line, 1);
							itfmBak->line = CUtil::TrimString(itfmBak->line, 1);
							if (iter->line.empty())
								result->comment_lines++;	// whole line
							else
								result->e_comm_lines++;		// embedded
						}

						// quote chars found may be erased as it is inside comment
						quote_idx_start = idx_start;
					}
					break;
				default:
					cout << "Error in CountCommentsSLOC()" << endl;
					break;
				}
			}
		}
	}
	return 1;
}
/*!
* Counts the number of comment lines, removes comments, and
* replaces quoted strings by special chars, e.g., $
* All arguments are modified by the method.
*
* \param fmap list of processed file lines
* \param result counter results
* \param fmapBak list of original file lines (same as fmap except it contains unmodified quoted strings)
*
* \return method status
*/
int CFortranCounter::CountCommentsSLOC(filemap* fmap, results* result, filemap *fmapBak)
{
	if (LineCommentStart.empty())
		return 0;
	if (classtype == UNKNOWN || classtype == DATAFILE)
		return 0;

	bool contd_nextline;
	int comment_type = 0;
	/*
	comment_type:
	0 : not comment
	1 : line comment, whole line
	2 : line comment, embedded
	*/

	size_t i, idx_start, comment_start;
	size_t quote_idx_start;
	string curBlckCmtStart, curBlckCmtEnd, prevLine;
	char CurrentQuoteEnd = 0;
	bool quote_contd = false, found, foundSpc;
	filemap::iterator itfmBak = fmapBak->begin();

	quote_idx_start = 0;
	prevLine = "";

	for (filemap::iterator iter = fmap->begin(); iter != fmap->end(); iter++, itfmBak++)
	{
		contd_nextline = false;

		quote_idx_start = 0;
		idx_start = 0;

		if (CUtil::CheckBlank(iter->line))
			continue;
		if (quote_contd)
		{
			// replace quote until next character
			ReplaceQuote(iter->line, quote_idx_start, quote_contd, CurrentQuoteEnd);
			prevLine = itfmBak->line;
			if (quote_contd)
				continue;
		}

		while (!contd_nextline && idx_start < iter->line.length())
		{
			quote_idx_start = FindQuote(iter->line, QuoteStart, quote_idx_start, QuoteEscapeFront);
			comment_start = idx_start;

			// check for comment delimiters 'C', 'c' in col 1 (works for most cases)
			found = false;
			if ((iter->line[0] == 'C' || iter->line[0] == 'c') &&
				(prevLine.length() < 1 || prevLine[prevLine.length() - 1] != '&'))
			{
				// check for reserved 'c' words
				for (vector<string>::iterator viter = c_keywords.begin(); viter != c_keywords.end(); viter++)
				{
					if (CUtil::FindKeyword(iter->line, *viter, 0, TO_END_OF_STRING, false) == 0)
					{
						found = true;
						break;
					}
				}
				if (!found)
				{
					// check for function or assignment (check for 'c__()' or 'c__ =')
					foundSpc = false;
					for (i = 1; i < iter->line.length(); i++)
					{
						if (iter->line[i] == '(')
						{
							found = true;
							break;
						}
						else if (iter->line[i] == '=')
						{
							if (i >= iter->line.length() - 1 || iter->line[i + 1] != '=')
								found = true;
							break;
						}
						else if (iter->line[i] == ' ')
							foundSpc = true;
						else if (foundSpc)
							break;
					}
				}
				found = !found;
			}

			// check for comment delimiters '*', '!' in col 1
			if (found || ((iter->line[0] == '*' || iter->line[0] == '!') &&
				(prevLine.length() < 1 || prevLine[prevLine.length() - 1] != '&')))
			{
				comment_start = 0;
				comment_type = 1;
			}
			// commented out to favor Fortran 90+ (in Fortran 77 any character in column 6 indicates continuation, not comment)
			// else if (iter->line.length() > 6 && iter->line[5] == '!' && CUtil::CheckBlank(iter->line.substr(0, 5)))
			//	comment_start = string::npos;
			else
			{
				FindCommentStart(iter->line, comment_start, comment_type, curBlckCmtStart, curBlckCmtEnd);
				if (comment_start != string::npos)
				{
					// check for characters before comment
					for (i = 0; i < comment_start; i++)
					{
						if (iter->line[i] != ' ')
						{
							comment_type = 2;
							break;
						}
					}
				}
			}

			if (comment_start == string::npos && quote_idx_start == string::npos)
			{
				prevLine = itfmBak->line;
				break;
			}

			if (comment_start != string::npos)
				idx_start = comment_start;

			// if found quote before comment
			if (quote_idx_start != string::npos && (comment_start == string::npos || quote_idx_start < comment_start))
			{
				ReplaceQuote(iter->line, quote_idx_start, quote_contd, CurrentQuoteEnd);
				if (quote_idx_start > idx_start)
				{
					if (quote_contd)
					{
						if (itfmBak->line[itfmBak->line.length() - 1] == '&')
						{
							iter->line[iter->line.length() - 1] = '&';
							if (itfmBak->line.length() > 2 && itfmBak->line[itfmBak->line.length() - 2] == ' ')
								iter->line[iter->line.length() - 2] = ' ';
						}
					}
					idx_start = quote_idx_start;
					prevLine = itfmBak->line;
					continue; // comment delimiter inside quote
				}
			}
			else if (idx_start != string::npos)
			{
				 // comment delimiter starts first
				switch(comment_type)
				{
				case 1:	// line comment, definitely whole line
				case 3:
					prevLine = "";
					iter->line = "";
					itfmBak->line = "";
					result->comment_lines++;
					contd_nextline = true;
					break;
				case 2:	// line comment, possibly embedded
				case 4:
					result->e_comm_lines++;
					prevLine = "";
					iter->line = iter->line.substr(0, idx_start);
					itfmBak->line = itfmBak->line.substr(0, idx_start);
					// trim trailing space
					iter->line = CUtil::TrimString(iter->line, 1);
					itfmBak->line = CUtil::TrimString(itfmBak->line, 1);
					if (iter->line.empty())
						result->comment_lines++;	// whole line
					else
						result->e_comm_lines++;		// embedded
					contd_nextline = true;
					break;
				default:
					cout << "Error in CountCommentsSLOC()";
					break;
				}
			}
		}
	}
	return 1;
}