At the beginning of 2024, I ragequit reading about Psion’s proprietary Object Oriented C.

This was unexpected, but I should have seen it coming.

Near the end of the previous November, I made an announcement on social media. I was going to start working on a new word processor for Psion’s 16-bit portable machines. I’d been working on Psion-related projects since September 2018, focusing on the SIBO/EPOC16 platform. Writing a replacement for Psion Word was one of the first ideas I’d had. So, as I’d spent the latter half of 2023 bouncing between projects and never quite settling, I decided that now was the time. It was to be called Vine, a nod to both the codename of the Psion Siena and the Vi-like bindings I was hoping to include in its feature set.

When developing graphical applications for EPOC16, the operating system that ran on almost all SIBO machines, Psion recommended using their Object Oriented C. This is a completely proprietary set of OO libraries and tools with its own class definition language, designed specifically (and exclusively) for use with EPOC16.

I had spent the previous few years slowly picking my way through the SIBO C SDK, the software development kit that targets devices like the Series 3a pocket computer. I had really enjoyed writing small EPOC16 apps using PLIB, Psion’s C dialect. The documentation is very comprehensive – it assumes almost no prior knowledge of programming, walking you through the basics of writing C code for the SIBO platform. Some of the underlying decisions felt unconventional, even to my untrained eye, but there was nothing that had truly frustrated me. I hadn’t touched the OO parts of the SDK yet. So, over the Christmas break, I grabbed a PDF of the SDK’s Object Oriented Programming Guide and settled down for some light holiday season reading.

The Guide starts off in a similar way to the PLIB manual. It describes the basic concepts of object oriented programming – classes, categories, message passing. It talks about the specifics of Psion’s OO C, such as libraries and various conventions. It then goes on to talk about Psion category files and introduces us to CTRAN, the category file preprocessor. At first glance of the format, it all looks simple enough. You have includes, class declarations, method declarations, types, and property (singular). There are even a few lines of what look like C. But there seem to be comments in weird places. Is that allowed? Are they just annotations in the documentation?

It was at about this point that I thought I’d try to compile a Psion OO C app. I already had the SDK set up in DOSBox Staging, so this wouldn’t be too tricky. As I worked through the examples in the SDK and compiled some other projects from GitHub, I noticed that the SDK’s INCLUDE folder was filling up with .G files. So, I tried to alter the projects to put the files elsewhere.

The location of external category files is specified using the -e switch. But CTRAN can’t include external category files from more than one location. If I want to include OLIB or another file in the SDK (i.e. -eC:\SIBOSDK\INCLUDE), you can’t also include a file from inside your own project. And you always want to include OLIB, because that’s where the root class is. This is a theme across almost all of the SDK tools, and basically means that any new files generated by the SDK’s tools have to be stored inside the SDK’s main include folder.

You also can’t specify an absolute path inside a category file. Using the -e switch multiple times fails with an error. Separating a path using a comma or a semicolon also fails.

This wasn’t a mistake either. Psion’s own scripts actively encouraged this. If you use the TopSpeed compiler’s build system to process a category file with CTRAN, it looks for existing files and puts newly generated header files in C:\SIBOSDK\INCLUDE folder by default.

You end up with an INCLUDE folder that you either have to regularly clean, or you accept that it will be a dumping ground for every project you compile. Beware if you have files with the same name in multiple projects!

This, frankly, made my brain itch. In my humble opinion, the SDK folder should be sacred, untouched by the tendrils of external projects. Stashing generated C headers and resource files is just a recipe for untidiness. The toolchain must remain pure!

To me, this was something that an experienced programmer could have added in an hour or two. Heck, I thought, even I could have done it in a few hours.

I decided I could do it better.

I was going to rewrite CTRAN. I’d rewrite the whole SDK if I had to, including the compiler. I was a petulant child, convinced the grown-ups were doing it all wrong.

I established the main principles of the project. I spent a few days looking for a suitable language and compiler to use. Finally, I set up my environment and I got to work. And, after a few months, I got something working. It even works better than the original.

To paraphrase the Reverend Jagger, you don’t always get the project you want, but you might sometimes get the project you need.

The Plan#

The new CTRAN would be the following:

  1. Open source
  2. Run on as many modern operating systems as possible (Linux, macOS, Windows, *BSD, Haiku)
  3. Be a drop-in replacement for the original CTRAN, so would need to…
  4. Run on DOS (or at least DOSBox)
  5. Allow multiple paths for includes in category files (this was obviously the most important thing)

Pascal?#

I’ve never written anything like this before, so I wanted to use a language that would get out of my way. I wanted something that would let me start coding at a relatively high level, so that I could focus on getting something working. But I wanted the option to be able to go lower if I needed to or wanted to. Finally, the compiler needed to be able to target modern operating systems and DOS, with minimal work. I also wanted type safety.

After ruling out C, C++, Rust, Go, and a few others, I settled on Object Pascal. The Free Pascal compiler can target pretty much anything, including DOS. The standard libraries are good, too. Object Pascal lets me write simple code so that I can get on with the job, but will also let me mess directly with pointers and manual memory management if I want to.

Pascal also scratched an itch in my brain. The novelty of using a language that is generally believed to be old fashioned was really appealing. As time went on, I was to find out that I really enjoy writing code in it.

“Make it work”#

I subscribe to Kent Beck’s “make it work, make it right, make it fast”. I also believe that if a job’s worth doing, it’s worth doing poorly.

The new CTRAN is far from perfect. Seasoned software developers may think that some of the decisions I’ve made are amateurish. That’s because they are. Although I have been programming on and off since the age of 7, I don’t have any formal Computer Science education. Concepts like binary trees, tokenisation, ASTs, etc, were unknown to me when I started working on this. So far, the project has no unit testing. There are almost certainly better ways of doing a lot of what I’ve done, but in the end that doesn’t matter. See the previous paragraph.

What is documented here is the “make it work” phase. I can make it “right” later.

This Series#

The following posts (chapters?) will lay out how I cobbled together a working replacement for CTRAN using the SDK documentation and black box testing.

I won’t necessarily mention things in chronological order. After all, this isn’t a novel. If it makes sense to mention something out-of-time but in context, I will.