import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
public class JavaScanner {
public static class Count {
int nbCommentsLines;
int nbJavadocsLines;
int nbLinesCode;
int nbBlankLines;
int nbLinesTotal;
void add(Count count) {
nbJavadocsLines += count.nbJavadocsLines;
nbCommentsLines += count.nbCommentsLines;
nbLinesCode += count.nbLinesCode;
nbBlankLines += count.nbBlankLines;
nbLinesTotal += count.nbLinesTotal;
}
void printHeaders(Writer w) throws IOException {
w.write("javadocs\t");
w.write("comments\t");
w.write("loc\t");
w.write("blank\t");
w.write("total\n");
w.flush();
}
void print(Writer w) throws IOException {
w.write(nbJavadocsLines + "\t");
w.write(nbCommentsLines + "\t");
w.write(nbLinesCode + "\t");
w.write(nbBlankLines + "\t");
w.write(nbLinesTotal + "\n");
w.flush();
}
}
private boolean first = true;
private int current, next;
private final StringBuilder buffer = new StringBuilder();
public Count count(File f) throws IOException {
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(f);
br = new BufferedReader(fr);
return count(br);
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException ex2) {
ex2.printStackTrace();
}
}
}
}
public Count count(Reader br) throws IOException {
first = true;
int c;
boolean inBlocComments = false;
boolean javadocs = false;
boolean javadocsInLine = false;
boolean commentsInLine = false;
boolean otherChars = false;
buffer.setLength(0);
Count count = new Count();
boolean inSingleLineComment = false;
while ((c = readChar(br)) != -1) {
// Windows : \r\n
// Mac : \r
// Unix : \n
if (c == '\r' || c == '\n') {
if (c == '\r' && next == '\n')
readChar(br); // eat up the '\n'
if (inBlocComments && !javadocs
|| commentsInLine && !javadocsInLine && !otherChars
|| inSingleLineComment) {
count.nbCommentsLines++;
//System.err.print("COMMENT : " + buffer);
} else if (inBlocComments && javadocs
|| javadocsInLine && !otherChars) {
count.nbJavadocsLines++;
//System.err.print("JAVADOC : " + buffer);
} else if (!commentsInLine && otherChars) {
count.nbLinesCode++;
//System.err.print("CODE : " + buffer);
} else if (!commentsInLine && !otherChars) {
count.nbBlankLines++;
//System.err.print("BLANK : " + buffer);
}
count.nbLinesTotal++;
if (next == -1)
return count;
otherChars = false;
if (!inBlocComments) {
commentsInLine = false;
javadocsInLine = false;
}
buffer.setLength(0);
inSingleLineComment = false;
} else if (inSingleLineComment) {
} else if (c == '*') {
if (next == '/') {
readChar(br); // loose the '/'
inBlocComments = false;
javadocs = false;
continue;
}
} else if (!inBlocComments && c == '/') {
if (next == '*') {
readChar(br); // loose the '*'
if (next == '*') {
javadocs = true;
javadocsInLine = true;
}
inBlocComments = true;
commentsInLine = true;
continue;
} else if (next == '/')
inSingleLineComment = true;
} else if (c == ' ' || c == '\t') {
} else if (!inBlocComments) {
otherChars = true;
}
}
// same as end of line
if (inBlocComments && !javadocs
|| commentsInLine && !otherChars
|| inSingleLineComment) {
count.nbCommentsLines++;
//System.err.print("COMMENT : " + buffer);
} else if (inBlocComments && javadocs
|| javadocsInLine && !otherChars) {
count.nbJavadocsLines++;
//System.err.print("JAVADOC : " + buffer);
} else if (!commentsInLine && otherChars) {
count.nbLinesCode++;
//System.err.println("CODE : " + buffer);
} else if (!commentsInLine && !otherChars) {
count.nbBlankLines++;
//System.err.println("BLANK : " + buffer);
}
count.nbLinesTotal++;
return count;
}
private int readChar(Reader r) throws IOException {
if (first) {
current = r.read();
if (current != -1)
next = r.read();
else
next = -1;
first = false;
} else {
current = next;
next = r.read();
}
if (current != -1)
buffer.append((char)current);
return current;
}
}
How many comment lines does your program count for this code:
public class LineCounterBreaker
{
/** This tries to confuse the line counter.
* @param args String []
*/
public static void main( String [] args )
{
String quote commentChars = "/**";
/** This is not a Javadoc comment. */
System.out.println( "Comment chars = "+ commentChars + "/*" );
commentChars += "/*"; // is this a comment line or a non-comment
line? /*
commentChars += "//"; /* // is this a comment line? */
/** Is the next line a comment line? This is not a Javadoc
comment either */
commentChars += "/*";
}
}
Out of 16 lines I count 3 Javadoc lines, 2 comment lines, and 11
regular lines. What does your program show?
--
Lew
> i'd like to share this simple java parser. The aim is to
> count the 4 types of lines: blank, code, comments, javadocs
> and the total. If you use it, and find flaws in it, please
> answer to the post.
[...]
Alternatively, SourceMeter [1] uses a JavaCC generated parser
to examine Java source code. I've adapted [2] it to count
constructors, fields an d methods; but the parser recognizes
SINGLE_LINE_COMMENT, MULTI_LINE_COMMENT and FORMAL_COMMENT
tokens, among others. As a side effect it detects syntactically
incorrect programs. For example,
$ unzip ../SourceMeter-0.5.zip
$ patch -p0 < ../patch6.txt
$ ant build
$ ls -1 *.java
LineCounterBreaker.java
$ java -jar SourceMeter.jar .
Java parse error
In retrospect, that's a bit cryptic; on compilable code, it's
not bad:
$ java -jar SourceMeter.jar src
FC Number of processed files
JCON Number of Java constructors
JFLD Number of Java field definitions
JMTH Number of Java method definitions
LOT Lines of text
LOTNE Non-empty lines of text
Dir FC JCON JFLD JMTH LOT LOTNE
root - - - - - -
sourcemeter 10 9 40 82 1,535 1,388
gauge 3 3 7 15 172 143
parser 1 0 0 1 34 29
java 7 13 210 579 9,653 9,006
parser 8 13 210 580 9,687 9,035
util 2 3 1 7 125 109
sourcemeter 23 28 258 684 11,519 10,675
root 23 28 258 684 11,519 10,675
[1]<http://sourceforge.net/projects/sourcemeter/>
[2]<http://sourceforge.net/tracker/?group_id=37608&atid=420208>
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>