| The Personal Software Process: an Independent Study | ||
|---|---|---|
| Prev | Chapter 2. Lesson 2: Planning and Measurement | Next |
Write a program to count program LOC.
From [Humphrey95]:
Requirements:Write a program to count the logical lines in a program, omitting comments and blank lines. Use the counting standard produced by report exercise R1 to place one logical line on each physical line and count physical lines. Produce a single count for the entire program source file.
Testing: Thoroughly test the program. As one test, count the LOC in [program 1A] and 2A. Submit these data with your homework results, using the format in Table D6:
Table 2-7. Test Results Format -- Program 2A
Program Number LOC 1A 2A
With the same philosophy I used in program 1A, I'm going to take input not from a file, but from standard input. This can be used to our advantage, particularly since under Linux we can use program 2A as an element in a pipe, and combine LOC counts from several different source files thusly:
Example 2-1. Counting many source files
[vputz@yak_prime lesson_2]$ cat *.{h,cpp} | ./psp_2a
LOC: 233 |
The program will NOT attempt to analyze the syntax or logical construction of the source code. It will simply count physical lines according to the coding standards
Sigh... I missed this entry in the planning worksheet and produced no size estimate for program 2A
This should have been done using a total size estimate and the %to date entries in the planning blocks. Instead, I took a brash guess for each phase, which serves me right for not paying closer attention to the planning script.
The basic design involves two classes: a simple_input_parser and a simple_loc_counter; the main() function simply invokes a simple_loc_counter to parse standard input.
The simple_input_parser class is indeed simple: once assigned an input stream, a call to simple_input_parser::parse_until_eof reads lines, one at a time, transforms them according to transformed_line, and stores the result in m_last_line. After each line is read, parse_until_eof calls parse_last_line to act on the last line read and transformed.
The simple_loc_counter class subclasses simple_input_parser; the transformation applied to each line is simple: leading and trailing whitespace is skipped. Each line is classified according to a number of functions such as last_line_is_comment, last_line_is_compiler_directive, etc. An integer counter takes care of "nested" block comments.
The simple_loc_counter class appends each LOC to a buffer of countable lines, and simply returns the size of that buffer (in LOC) when asked. It can also print each countable line, useful during testing.
Several problems were discovered in the compilation phase, mostly having to do with missing features in the interfaces (missing reset methods, missing min/max functionality, etc). Most of these were quickly fixed (1-2 minute fix times)
/*
*/
#ifndef SIMPLE_INPUT_PARSER_H
#define SIMPLE_INPUT_PARSER_H
#include <string>
#include <iostream>
//a standard "framework" for parsing a set of input lines
class simple_input_parser
{
public:
//sets input stream
void set_input_stream (istream * new_input);
//parse input until EOF
void parse_until_eof (void);
//reads single line from input, transforms it, stores it in last_line
void read_line (void);
//sets the last line read
void set_last_line (const std::string & new_line);
//last line read from input
const std::string & last_line (void) const;
//parses the last line read
virtual void parse_last_line (void);
//returns a "transformed" copy of the given line
virtual std::string transformed_line (const std::string & line) const;
//constructor
simple_input_parser (void);
//virtual destructor
virtual ~ simple_input_parser (void);
//resets the parser
virtual void reset (void);
private:
//the input stream
istream * m_input_stream;
//the last line of input
std::string m_last_line;
};
#endif
/*
*/ |
/*
*/
#include "simple_input_parser.h"
#ifndef CONTRACT_H
#include "contract.h"
#endif
void
simple_input_parser::set_input_stream (istream * new_input)
{
m_input_stream = new_input;
}
void
simple_input_parser::parse_until_eof (void)
{
REQUIRE (m_input_stream != NULL);
while (!(m_input_stream->eof ()))
{
read_line ();
parse_last_line ();
}
}
void
simple_input_parser::read_line (void)
{
REQUIRE (!(m_input_stream->eof ()));
const int
input_buffer_size = 255;
char
input_buffer[input_buffer_size];
m_input_stream->getline (input_buffer, input_buffer_size);
//for some reason, the G++ standard library needs me to do this or it
//doesn't register the EOF condition properly. This makes no sense
//to me...
char c = m_input_stream->get();
m_input_stream->putback( c );
std::string input_line (input_buffer);
//no source code line should be longer than 255!
CHECK (input_line.size () < 255);
set_last_line (transformed_line (input_line));
}
void
simple_input_parser::set_last_line (const std::string & new_line)
{
m_last_line = new_line;
}
const
std::string & simple_input_parser::last_line (void) const
{
return m_last_line;
}
void
simple_input_parser::parse_last_line (void)
{
//basic version does nothing
}
std::string simple_input_parser::transformed_line (const std::string & line) const
{
return line;
}
simple_input_parser::simple_input_parser (void)
{
reset ();
}
simple_input_parser::~simple_input_parser (void)
{
}
void
simple_input_parser::reset (void)
{
m_input_stream = NULL;
m_last_line = "";
}
/*
*/ |
/*
*/
#ifndef SIMPLE_LOC_COUNTER_H
#define SIMPLE_LOC_COUNTER_H
#ifndef SIMPLE_INPUT_PARSER_H
#include "simple_input_parser.h"
#endif
#include <string>
#include <vector>
//subclass of simple_input_parser that stores countable lines of code in a buffer
//and can return their count.
class simple_loc_counter:public simple_input_parser
{
public:
//adds last line to the buffered lines if it is countable
void parse_last_line (void);
//the count of LOC
int loc_count (void) const;
//whether last line was comment
bool last_line_is_comment (void) const;
//whether last line was compiler directive
bool last_line_is_compiler_directive (void) const;
//whether we are in a block comment
bool is_in_block_comment (void) const;
//whether last line was part of a begin/end pair
bool last_line_is_begin_or_end (void) const;
//whether the last line was countable
bool last_line_is_countable (void) const;
//whether the last line was empty
bool last_line_is_empty (void) const;
//updates the block comment count
void update_block_comment_count (void);
//whether the last line starts with the given string
bool last_line_starts_with (const std::string & search_string) const;
//whether a given string starts with a search string
static bool string_starts_with (const std::string & given_string,
const std::string & search_string);
//returns the input string stripped of leading/trailing whitespace
std::string string_stripped_of_whitespace (const std::string & input_string) const;
//returns the transformed line (here, the line stripped of whitespace)
virtual std::string transformed_line (const std::
string & input_string) const;
//constructor
simple_loc_counter (void);
//destructor
virtual ~ simple_loc_counter (void);
//resets the object
void reset (void);
//writes the countable lines to the given output stream
void write_countable_lines (ostream & ostr) const;
protected:
//the buffered countable lines
std::vector < std::string > m_countable_lines;
//the "block comment" nesting level
int m_block_comment_nesting_level;
//the beginning of a block comment
static const std::string & block_comment_begin;
//the end of a block comment
static const std::string & block_comment_end;
//the beginning of an inline comment
static const std::string & inline_comment_begin;
//the beginning of a compiler directive
static const std::string & compiler_directive_begin;
//the "begin block" string
static const std::string & block_begin;
//the "end block" string
static const std::string & block_end;
//whitespace characters
static const std::string & whitespace_characters;
};
#endif
/*
*/ |
/*
*/
#include "simple_loc_counter.h"
#ifndef YAK_MIN_MAX_H
#include "yak_min_max.h"
#endif
void
simple_loc_counter::parse_last_line (void)
{
if (last_line_is_countable ())
{
m_countable_lines.push_back (last_line ());
}
}
int
simple_loc_counter::loc_count (void) const
{
return m_countable_lines.size ();
}
bool
simple_loc_counter::last_line_is_comment (void) const
{
bool Result = false;
if (last_line_starts_with (block_comment_begin)
|| last_line_starts_with (inline_comment_begin)
|| is_in_block_comment ())
{
Result = true;
}
return Result;
}
bool
simple_loc_counter::last_line_is_compiler_directive (void) const
{
bool Result = false;
if (last_line_starts_with (compiler_directive_begin))
{
Result = true;
}
return Result;
}
bool
simple_loc_counter::is_in_block_comment (void) const
{
bool Result = false;
if (m_block_comment_nesting_level > 0)
{
Result = true;
}
return Result;
}
bool
simple_loc_counter::last_line_is_begin_or_end (void) const
{
bool Result = false;
if (last_line_starts_with (block_begin)
|| last_line_starts_with (block_end))
{
Result = true;
}
return Result;
}
bool
simple_loc_counter::last_line_is_empty (void) const
{
return (last_line ().length () == 0);
}
bool
simple_loc_counter::last_line_is_countable (void) const
{
bool Result = true;
if ((last_line_is_comment ())
|| (last_line_is_begin_or_end ())
|| (last_line_is_compiler_directive ()) || (last_line_is_empty ()))
{
Result = false;
}
return Result;
}
void
simple_loc_counter::update_block_comment_count (void)
{
//count through the string; add 1 to the block comment count if the begin
//string is encountered, subtract one if the end string is encountered.
for (unsigned int i = 0; i < last_line ().length (); ++i)
{
std::string line_remaining =
last_line ().substr (i, last_line ().length ());
if (string_starts_with (line_remaining, block_comment_begin))
{
++m_block_comment_nesting_level;
}
else if (string_starts_with (line_remaining, block_comment_end))
{
--m_block_comment_nesting_level;
}
}
}
bool
simple_loc_counter::
last_line_starts_with (const std::string & search_string) const
{
return string_starts_with (last_line (), search_string);
}
bool
simple_loc_counter::string_starts_with (const std::string & given_string,
const std::string & search_string)
{
int
substring_size =
yak_min (given_string.length (), search_string.length ());
std::string substring = given_string.substr (0, substring_size);
bool Result = (substring == search_string);
return Result;
}
std::string
simple_loc_counter::
string_stripped_of_whitespace (const std::string & input_string) const
{
std::string::size_type start =
input_string.find_first_not_of (whitespace_characters);
if (start == input_string.npos)
{
start = 0;
}
std::string::size_type end =
input_string.find_last_not_of (whitespace_characters);
if (end == input_string.npos)
{
end = 0;
}
std::string Result = input_string.substr (start, (end == 0) ? 0 : end + 1);
return Result;
}
std::string
simple_loc_counter::transformed_line (const std::string & input_string) const
{
return string_stripped_of_whitespace (input_string);
}
simple_loc_counter::simple_loc_counter (void)
{
reset ();
}
simple_loc_counter::~simple_loc_counter (void)
{
}
void
simple_loc_counter::reset (void)
{
m_countable_lines.clear ();
m_block_comment_nesting_level = 0;
}
void
simple_loc_counter::write_countable_lines (ostream & ostr) const
{
for (std::vector < std::string >::const_iterator iter =
m_countable_lines.begin (); iter != m_countable_lines.end (); ++iter)
{
ostr << *iter << "\n";
}
}
const
std::string & simple_loc_counter::block_comment_begin = "/*";
const
std::string & simple_loc_counter::block_comment_end = "*/";
const
std::string & simple_loc_counter::inline_comment_begin = "//";
const
std::string & simple_loc_counter::compiler_directive_begin = "#";
const
std::string & simple_loc_counter::block_begin = "{";
const
std::string & simple_loc_counter::block_end = "}";
const
std::string & simple_loc_counter::whitespace_characters = " \t\n\0x32";
/*
*/ |
/*
*/
#ifndef SIMPLE_LOC_COUNTER_H
#include "simple_loc_counter.h"
#endif
istream *
input_stream_from_args (int arg_count, const char **arg_vector)
{
istream *Result = NULL;
if (arg_count == 1)
{
Result = &cin;
}
else
{
const char *help_text = "PSP exercise 2A: Count the physical LOC from standard input\n according to the style and counting guidelines in reports \n 1A and 2A. \n \n Usage:\n \tpsp_2a \n \n";
cout << help_text;
}
return Result;
}
int
main (int arg_count, const char **arg_vector)
{
//get the input stream, or print the help text as appropriate
istream *input_stream = input_stream_from_args (arg_count, arg_vector);
if (input_stream != NULL)
{
simple_loc_counter counter;
counter.set_input_stream (input_stream);
counter.parse_until_eof ();
//output the loc
cout << "LOC: " << counter.loc_count () << "\n";
}
}
/*
*/ |
deferred class SIMPLE_INPUT_PARSER
feature {ANY}
parse_until_eof is
--parses all input until an EOF is reached
require
input_stream /= Void;
do
from
until
input_stream.end_of_input
loop
read_line;
if not input_stream.end_of_input then
parse_last_line;
end;
end;
end -- parse_until_eof
set_input(new_input_stream: INPUT_STREAM) is
--sets the input stream
do
input_stream := new_input_stream;
end -- set_input
read_line is
--reads a line from standard input
do
input_stream.read_line;
last_line := transformed_line(input_stream.last_string);
end -- read_line
last_line: STRING;
input_stream: INPUT_STREAM;
parse_last_line is
deferred
end -- parse_last_line
transformed_line(to_transform: STRING): STRING is
--transforms the line according to rules defined in subclasses
do
Result := to_transform;
end -- transformed_line
end -- class SIMPLE_INPUT_PARSER |
class SIMPLE_LOC_COUNTER
-- counts one form of LOC in eiffel files
inherit
SIMPLE_INPUT_PARSER
redefine parse_last_line, transformed_line
end;
creation {ANY}
make
feature {ANY}
make is
do
!!counted_lines.make(1,0);
end -- make
parse_last_line is
-- store countable lines in an array
do
if last_line_is_countable then
counted_lines.add_last(last_line);
end;
end -- parse_last_line
counted_lines: ARRAY[STRING];
--array containing countable lines
loc_count: INTEGER is
-- number of lines counted as LOC
do
Result := counted_lines.count;
end -- loc_count
last_line_is_comment: BOOLEAN is
do
if last_line_starts_with(comment_begin) then
Result := true;
else
Result := false;
end;
end -- last_line_is_comment
comment_begin: STRING is "--";
last_line_is_compiler_directive: BOOLEAN is false;
in_block_comment: BOOLEAN is false;
last_line_starts_with(test_string: STRING): BOOLEAN is
do
if last_line.has_prefix(test_string) then
Result := true;
else
Result := false;
end;
end -- last_line_starts_with
last_line_is_countable: BOOLEAN is
do
if last_line_is_comment or last_line_is_begin_or_end or last_line_is_empty then
Result := false;
else
Result := true;
end;
end -- last_line_is_countable
last_line_is_begin_or_end: BOOLEAN is
do
if last_line_starts_with("do") or last_line_starts_with("end") then
Result := true;
else
Result := false;
end;
end -- last_line_is_begin_or_end
last_line_is_empty: BOOLEAN is
do
if last_line.empty then
Result := true;
else
Result := false;
end;
end -- last_line_is_empty
transformed_line(string: STRING): STRING is
do
Result := string_stripped_of_whitespace(string);
end -- transformed_line
string_stripped_of_whitespace(string: STRING): STRING is
do
Result := string.twin;
Result.replace_all('%T',' ');
Result.left_adjust;
Result.right_adjust;
end -- string_stripped_of_whitespace
print_counted_lines(output: OUTPUT_STREAM) is
local
index: INTEGER;
do
from
index := counted_lines.lower;
until
not counted_lines.valid_index(index)
loop
output.put_string(counted_lines.item(index));
output.put_string("%N");
index := index + 1;
end;
end -- print_counted_lines
end -- class SIMPLE_LOC_COUNTER |
class MAIN
creation {ANY}
make
feature {ANY}
make is
local
simple_loc_counter: SIMPLE_LOC_COUNTER;
do
!!simple_loc_counter.make;
simple_loc_counter.set_input(io);
simple_loc_counter.parse_until_eof;
std_output.put_string("LOC: ");
std_output.put_integer(simple_loc_counter.loc_count);
end -- make
end -- class MAIN |
Minor problems in the compile phase; most of these were relatively straightforward typos from the coding phase (forgot to clean up "virtual" keyword when editing copied text, forgot to add simple_loc_counter:: to a declaration, etc). Most were quickly fixed, except for a 7-minute period where I had to jockey makefiles to get them to work properly.
Ah, testing. Many problems were discovered here, and while some were easy to fix (evidently the standard C++ string class-- or at least this implementation-- gives different results between length and size...), some were downright tricky (if the standard C++ string class doesn't find what it's looking for in find_first_not_of or find_last_not_of, it returns a mysterious value, npos-- I confess I was expecting the length of the string or some such. This occupied about 21 minutes of the testing phase).
My decision to allow the simple_loc_counter class to print counted lines made testing much nicer, as I could more easily compare what the program was actually counting to what was in the submitted files.
As per the testing requirements, I have used program 2A to calculate LOC counts for programs 1A and 2A:
Table 2-8. Loc Results -- Program 2A, C++
| Program Number | LOC |
| 1A | 94 |
| 2A | 233 |
Table 2-9. Loc Results -- Program 2A, Eiffel
| Program Number | LOC |
| 1A | 82 |
| 2A | 95 |
Table 2-10. Project Plan Summary
| Student: | Victor B. Putz | Date: | 991228 |
| Program: | LOC counter | Program# | 2A |
| Instructor: | Wells | Language: | C++ |
| Program Size | Plan | Actual | To date |
| Base | 0 | ||
| Deleted | 0 | ||
| Modified | 0 | ||
| Added | 233 | ||
| Reused | 0 | 0 | |
| Total New and Changed | (no planned size) | 233 | 233 |
| Total LOC | 233 | 233 | |
| Total new/reused |
| Time in Phase (min): | Plan | Actual | To Date | To Date% |
| Planning | 10 | 10 | 24 | 7 |
| Design | 30 | 27 | 44 | 13 |
| Code | 60 | 75 | 99 | 30 |
| Compile | 20 | 26 | 31 | 9 |
| Test | 45 | 59 | 110 | 34 |
| Postmortem | 10 | 17 | 20 | 6 |
| Total | 175 | 214 | 328 | 100 |
| Defects Injected | Actual | To Date | To Date % | |
| Plan | 0 | 0 | 0 | |
| Design | 11 | 11 | 26 | |
| Code | 19 | 27 | 63 | |
| Compile | 1 | 2 | 5 | |
| Test | 0 | 3 | 7 | |
| Total development | 31 | 43 | 100 | |
| Defects Removed | Actual | To Date | To Date % | |
| Planning | 0 | 0 | 0 | |
| Design | 0 | 0 | 0 | |
| Code | 11 | 11 | 26 | |
| Compile | 11 | 18 | 42 | |
| Test | 9 | 14 | 33 | |
| Total development | 31 | 43 | 100 | |
| After Development | 0 | 0 |
| Eiffel code/compile/test |
| Time in Phase (min) | Actual | To Date | To Date % |
| Code | 31 | 46 | 53 |
| Compile | 18 | 28 | 32 |
| Test | 5 | 13 | 15 |
| Total | 54 | 87 | 100 |
| Defects Injected | Actual | To Date | To Date % |
| Design | 3 | 3 | 13 |
| Code | 14 | 20 | 87 |
| Compile | 0 | 0 | 0 |
| Test | 0 | 0 | 0 |
| Total | 17 | 23 | 100 |
| Defects Removed | Actual | To Date | To Date % |
| Code | 1 | 1 | 4 |
| Compile | 11 | 14 | 61 |
| Test | 5 | 8 | 35 |
| Total | 17 | 23 | 100 |
Table 2-11. Time Recording Log - C++
| Student: | Victor B. Putz | Date: | 991219 |
| Instructor: | Wells | Program# | 1A |
| Start | Stop | Interruption Time | Delta time | Phase | Comments |
| 991228 10:56:15 | 991228 11:25:13 | 1 | 27 | design | |
| 991228 11:28:59 | 991228 12:48:48 | 4 | 75 | code | |
| 991228 12:49:09 | 991228 13:15:23 | 0 | 26 | compile | |
| 991228 13:15:45 | 991228 14:15:25 | 0 | 59 | test | |
| 991228 14:58:59 | 991228 15:19:37 | 3 | 17 | postmortem | |
Table 2-12. Time Recording Log - Eiffel
| Student: | Victor B. Putz | Date: | 000104 |
| Instructor: | Wells | Program# | 2A |
| Start | Stop | Interruption Time | Delta time | Phase | Comments |
| 000104 14:08:00 | 000104 14:39:23 | 0 | 31 | code | |
| 000104 14:39:29 | 000104 14:58:26 | 0 | 18 | compile | |
| 000104 15:00:37 | 000104 15:16:01 | 0 | 15 | test | |
Table 2-13. Defect Recording Log - C++
| Student: | Victor B. Putz | Date: | 991228 |
| Instructor: | Wells | Program# | 2A |
| Defect found | Type | Reason | Phase Injected | Phase Removed | Fix time | Comments |
| 991228 11:54:19 | ic | om | design | code | 1 | Forgot to add setter method for last_line |
| 991228 11:58:06 | ic | om | design | code | 1 | Forgot to add reset method |
| 991228 12:08:01 | ic | om | design | code | 2 | Added last_line_starts_with method |
| 991228 12:12:39 | ic | om | design | code | 1 | Added compiler_directive_begin string |
| 991228 12:15:30 | ic | om | design | code | 1 | Added block begin/end strings |
| 991228 12:18:56 | id | ty | design | code | 1 | renamed "is_last_line..." methods to "last_line_is..." |
| 991228 12:24:17 | ic | om | design | code | 2 | Had to add yak_min_max to get min, max functionality |
| 991228 12:26:54 | ic | om | code | code | 2 | Refactored last_line_starts_with into more generic string_starts_with method |
| 991228 12:35:45 | ic | om | design | code | 0 | Added whitespace_characters string |
| 991228 12:38:17 | ic | om | design | code | 1 | Added constructor and reset method |
| 991228 12:42:35 | ic | om | design | code | 1 | Added write_countable_lines method |
| 991228 12:49:50 | wn | ty | code | compile | 0 | Called "set_input" instead of "set_input_stream" |
| 991228 12:52:26 | id | om | code | compile | 1 | Forgot to add yak_defs, yak_exception to include path |
| 991228 12:56:19 | iu | ty | code | compile | 0 | |
| 991228 12:58:06 | wn | ty | code | compile | 0 | Mistyped name of last_line_is_countable |
| 991228 12:58:55 | wn | ty | code | compile | 0 | Didn't fully qualify std::string::size_type |
| 991228 13:00:17 | sy | om | code | compile | 0 | Forgot to clean up "virtual" from method declaration in .cpp file |
| 991228 13:01:15 | sy | om | code | compile | 0 | Forgot to add "simple_loc_counter::" to method declaration |
| 991228 13:02:52 | iu | om | code | compile | 0 | Misused const qualifier in method declaration for write_countable_lines |
| 991228 13:04:02 | iu | om | code | compile | 0 | Needed to add const qualifier in write_countable_lines |
| 991228 13:04:44 | sy | om | code | compile | 0 | Forgot to remove "static" from in-cpp declaration of class static variables |
| 991228 13:06:30 | iu | ex | compile | compile | 7 | Had to jockey the makefile setup to reuse some external code not meant for this reuse |
| 991228 13:20:28 | wn | kn | code | test | 4 | Used "size" instead of "length" for string length |
| 991228 13:25:22 | is | om | code | test | 1 | Forgot to add virtual destructors (warned by compiler) |
| 991228 13:27:43 | iu | om | code | test | 0 | Used "int" instead of "unsigned int" to compare to size() |
| 991228 13:28:25 | wn | om | code | test | 0 | Multiple uses of "size" instead of "length" for string length |
| 991228 13:30:41 | iu | kn | code | test | 21 | find_*_not_of return a mysterious "npos" when the string only contained the search characters. |
| 991228 13:54:32 | ic | om | design | test | 2 | Forgot to check for empty lines! |
| 991228 13:58:59 | iu | kn | code | test | 0 | Off-by-one; was not including the end character on string_stripped_of_whitespace |
| 991228 14:01:20 | iu | kn | code | test | 10 | Off-by-the-other-one; was including blank lines consisting of one space |
| 991228 14:12:07 | wa | kn | code | test | 1 | Was only checking for "}" to close blocks, discounting possible "};"... |
Table 2-14. Defect Recording Log - Eiffel
| Student: | Victor B. Putz | Date: | 000104 |
| Instructor: | Wells | Program# | 2A |
| Defect found | Type | Reason | Phase Injected | Phase Removed | Fix time | Comments |
| 000104 14:28:23 | ic | om | design | code | 3 | Adding last_line_starts_with method |
| 000104 14:39:40 | sy | ty | code | compile | 1 | forgot a comma |
| 000104 14:43:13 | is | om | code | compile | 0 | forgot to add return type in function declaration |
| 000104 14:44:28 | sy | ty | code | compile | 0 | Forgot to add "end" to end of class declaration |
| 000104 14:44:59 | sy | ty | code | compile | 0 | forgot to add "end" to deferred feature declaration |
| 000104 14:46:15 | sy | ty | code | compile | 0 | used "return result" semantics instead of "Result := result" semantics |
| 000104 14:46:56 | ic | ig | design | compile | 1 | forgot to add "last_line_is_countable" feature |
| 000104 14:49:02 | wn | cm | code | compile | 0 | Used "last_string" in feature name instead of "last_line" |
| 000104 14:50:36 | wn | cm | code | compile | 0 | Used "last_line" in feature name instead of "last_string" (external class) |
| 000104 14:51:34 | wn | om | code | compile | 2 | used "copy" instead of proper "twin" |
| 000104 14:54:50 | wn | cm | code | compile | 0 | Used "null" instead of "void" |
| 000104 14:56:19 | ic | om | code | compile | 1 | forgot to add "make" feature to simple_loc_counter |
| 000104 15:01:11 | ic | om | code | test | 2 | forgot to add "print_counted_lines" feature (for debugging) |
| 000104 15:03:50 | mi | cm | code | test | 1 | forgot to increment index in loop |
| 000104 15:06:34 | mi | cm | code | test | 1 | forgot to add newline to print_counted_lines |
| 000104 15:08:45 | wn | cm | code | test | 0 | changed "begin" constant to "do" constant (er... Eiffel doesn't use "begin") |
| 000104 15:09:16 | md | om | design | test | 4 | Er... forgot to exclude empty lines from count |