procedure charcount;
var
nc : integer;
c : character;
begin
nc := 0;
while (getc(c) <> ENDFILE) do
nc := nc + 1
putdec(nc, 1);
putc(NEWLINE);
end;
Freelance software grandad
software created
extended or repaired
Follow me on Mastodon
Applications, Libraries, Code
Talks & Presentations
STinC++ rewrites the programs in Software Tools in Pascal using C++
After devoting six pages to bootstrapping copy
, Kernighan and Plauger give their next program, charcount
, six sentences of setup. Of those six, three of them are an exhortation to just hang on and trust them
If you can’t think offhand why anyone would want to merely count the characters in something, don’t worry. This is a book on tool building, remember, and tools work best in combination. Applications will occur soon enough.
procedure charcount;
var
nc : integer;
c : character;
begin
nc := 0;
while (getc(c) <> ENDFILE) do
nc := nc + 1
putdec(nc, 1);
putc(NEWLINE);
end;
In their copy
program, they established they could read a character at a time from the standard input. For charcount
, it’s straightforward to modify the loop to keep a count of those characters.
Hmm. I was feeling smug about not having a loop in my implementation at all. Perhaps I’ll have to revisit the whole business?
I chose to treat the standard input as a sequence, and consequently was able to lean entirely on a function provided by C++'s standard library. Copying a sequence from one place to another is merely one of a number of operations the standard library provides. Another is std::distance(InputIt first, InputIt last)
, a function which returns the number of hops you need to advance from first
to last
.
In this case, passing in our istreambuf_iterators
it gives us the count of characters available on standard input. Again, the standard library provides exactly what’s needed.
#include "charcount.h"
#include <algorithm>
#include <iostream>
#include <iterator>
namespace stiX {
size_t charcount(std::istream &in) {
return std::distance(
std::istreambuf_iterator<char>(in),
std::istreambuf_iterator<char>()
);
}
}
While distance
maybe isn’t the best name, once you’re familiar with it this implementation is about as minimal and clear as it can be. Again, I’ve avoided an explicit loop, nor have I had to come up with any variable names. Even in a program as brief as charcount
Kernighan and Plauger’s version has a comprehension overhead. Their variable c
is, essentially, redundant. It’s only there so they can call the getc
primitive. The variable we really need to be paying attention to is nc
. However, because Pascal requires variables to declared ahead of the procedure body, all variables initially appear to be equally important. It’s a small thing here, but the larger the procedure the bigger a barrier it can be.
Rather than have the charcount
function write directly to the output, as Kernighan and Plauger did, I chose to return the count from the function and deal with the output higher up. In turn, this makes our test and executable drivers extremely plain.
void verifyCharCount(std::string input)
{
std::istringstream is(input);
auto count = stiX::charcount(is);
REQUIRE(count == input.size());
}
int main() {
std::cout << stiX::charcount(std::cin) << std::endl;
}
Source code for this program, indeed the whole project, is available in the stiX GitHub repository. charcount
is program 2 of Chapter 1.
This whole endeavour relies Software Tools in Pascal and Software Tools, both by Brian W Kernighan and PJ Plauger. I love these books and commend them to you. They’re both still in print, but there are plenty of second-hand editions floating round.
For this project I’ve been trying out JetBrain’s CLion, which so far has been pretty great. CLion uses CMake to build projects. My previous flirtations with CMake, admittedly many years ago, weren’t a huge success. Not so this time - it’s easy to use and works a treat.
The test harness I’m using is Catch. I’ve been aware of Catch pretty much since it was first released, but this is my first time really using it. I like it and will use it again.
Freelance software grandad
software created
extended or repaired
Follow me on Mastodon
Applications, Libraries, Code
Talks & Presentations