Jez Higgins

Freelance software grandad
software created
extended or repaired


Follow me on Mastodon
Applications, Libraries, Code
Talks & Presentations

Hire me
Contact

Older posts are available in the archive or through tags.

Feed

Yr glygfa o Hescwm Uchaf, rhif 5 : Until It’s In Your Hands

STinC++ rewrites the programs in Software Tools in Pascal using C++

I’ve been noodling away on this little amusement of writing the Kerninghan and Plauger’s software tools, of Software Tools and Software Tools in Pascal fame, in C++ for over four years now. We’ll get there. At the moment (and by moment, I mean past 15 months) I’m poking at edit, a cut down version of ed, the original Unix editor.

It’s actually at a place now where it’s usable - as usable as a line editor is anyway - so long as you don’t want to save anything. As I was finishing up for the evening, I was having a little play around and discovered that once I’d entered an erroneous command, every subsequent command, whether correct or not, errored as well.

Digging into the code, I quickly realised that the current line was being set to an error state, and just staying that way.

The fix was obvious, but then I looked again at the code and it just irked me.

auto line = stiX::getline(in); (1)

auto parsed_command = parse_command(line); (2)
auto command = parsed_command.compile(buffer_); (3)

buffer_.set_dot(command.dot); (4)

command(in, out, buffer_, filename_); (5)
  1. Read a line, which is some kind of command - 1,$p or something, normal vi talk

  2. Parse that line out

  3. Compile into a command. The command that comes back is always runnable. If the line we typed makes no sense, we return an error object. (Two patterns for the price of one 😮)

  4. Update the current line

  5. Execute the command

The obvious fix is tonot update the current line if we’re in an error state.

if (command.dot != line_error)
  buffer_.set_dot(command.dot);

That would be fine.

Except.

Except.

buffer_.set_dot(command.dot);

is arse-backward.

Instead of the command operating on buffer_, buffer_ is reaching into the command and doing something to itself. My obvious fix of

if (command.dot != line_error)
  buffer_.set_dot(command.dot);

was just going to make things even more horrible. What’s the point of a null object if you have to put in a special case for it?

So, I went off to bed resolved to fix it the following evening.

Grinding

It rubbed me wrong all day, just there in the back of my head. A few minutes, and I’d flip around from

buffer_.set_dot(command.dot);

to

command.apply_dot(buffer_);

or something like that, then it’d be all nice and neat, and I’d head into the next little piece of development happy.

All Change, Please! All Change!

I sat down, opened up CLion, loaded up the code, and now instead of thinking about one isolated line I was seeing it back in context

auto line = stiX::getline(in);

auto parsed_command = parse_command(line);
auto command = parsed_command.compile(buffer_);

buffer_.set_dot(command.dot);

command(in, out, buffer_, filename_);

What’s that?

buffer_.set_dot(command.dot);

command(in, out, buffer_, filename_);

buffer_ and command, followed by command and buffer_.

Doh

There shouldn’t be two calls. The set_dot call should be folded into the command execution. The conditional is inside command were it belongs, command is operating the on buffer_, not this pushmi-pullyu arrangement there was before, and the null object is properly preserved. It’s the easier change, the cleaner change, the better change.

Sometimes the code surprises you

I’d been intending to do the obvious change, 2 minute job, just to smooth things out, make it easier to read - but until you get the code in your hands, you never really know what it’s going to tell or what you’re going to do with it.

Endnotes

This whole endeavour relies on 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 are both still in print, but new copies are, frankly, ridiculously expensive. Happily, there are plenty of second-hand copies around, or you can borrow them from The Internet Archive using the links above.

For this project I’ve been using JetBrain’s CLion, right now the new CLion Nova. It certainly feels a quicker than the CLion Classic which, since I was happy enough to spend money on that, is more than enough for me.


Tagged code, and software-tools-in-c++


Jez Higgins

Freelance software grandad
software created
extended or repaired

Follow me on Mastodon
Applications, Libraries, Code
Talks & Presentations

Hire me
Contact

Older posts are available in the archive or through tags.

Feed