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 olygfa o Hescwm Uchaf, rhif 2 : STinC++ - The current line in ed/ex/vi/vim

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

Back on my slow stroll through rewriting Software Tools in Pascal in C++. This is a book I’ve read cover to cover I don’t know how many times in the past thirty years, but I find new facets in each time, and particularly as I’m writing code along with it.

We’re all (and by all I mean all Vim-speakers) familiar with the providing line numbers to a command - 1,$s/x/y/, .,.+10d - that kind of thing. Strictly speaking those are line expressions, rather than line numbers, but that starts to feel like splitting hairs.

But did you know, because I sure as hell didn’t, know you can provide an arbitrary number of line expressions?

When I read that Kernighan and Plauger’s edit could take any number of expressions, I thought it was just an implementation detail and didn’t really think anything about it.

I wrote my command parser to eat as many expressions as you give it, then just hand out the last two. Because that makes sense right? Treating 1,2,4,8,16d as 8,16d just seems sensible.

And then the other evening I read

A line number expression can be arbitrarily complex, so long as it lies between 0 and $, inclusive. And there can be any number of expressions, so long as the last one or two are legal for the particular command. Thus
\function\;\\
finds the second previous function declaration and
/begin/;//;//;//p
prints from the third succeeding line containing begin to the fourth, inclusive.

Whoa! What now?

For context, \<pattern>\ searches backwards, /<pattern>/ searches forward. \\ and // search backwards or forwards using the most recent pattern again. function and begin are Pascal keywords.

The key here is the difference between using , and ; as the separator between the line expressions.

A , is just a normal separator, but using ; updates the current line number to the value of the expression. That’s why the examples above do what they do. Without the ; the searches would just find the same line each time. With the power of ;, you can do all kinds of crazy stuff. I can’t think why you would, I mean I’ve lasted this long without knowing this stuff, but I’m already expecting to find out this is Turing complete[1].

That’s it?

That’s it!

That’s the key. Multiple line expressions aren’t a quirk of Kernighan and Plauger’s little line editor, it’s a deliberate part of ed, and consequently ex, and vi, and vim, and presumably other editors too.

Bananas.

My editor didn’t support ; properly. You could pop one in as a separator, but I’m wasn’t doing anything special with it.

Kernighan and Plauger’s editor operates as it parses each command. If they see a ; then just update the current line right there and then. That’s a reasonable choice given their various constraints - writing didactic code in Pascal, in late 70s, for people who’ve never heard of Unix, etc, etc.

My code has a hard divide between command parsing and executing those commands. If you give my editor a command that makes no sense, then nothing should happen. Either it all works, or nothing works. What can I say? I’ve taken the Abrahams guarantees to soul of my being.

To evaluate the line expressions, I need to update the current line without updating the current line while parsing, then actually update the current line when executing.

Look! A Squirrel!`

It all went pretty well. The first four commits were gentle preparations to actually pulling the trigger, and implementing the new functionality, all three lines of it, in the last commit.

(And then fixing a classic C++ blunder (function argument evaluation order!) to actually making it work.)

Actually, I realised afterwards, I pulled the trigger on half the functionality - evaluating the line expressions - but not updating the current line during command execution.

Nevermind. Next time.

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, which I liked enough to buy and keep renewing a license for. I use it all the time now.


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