You’ve probably noticed a trend in the last few articles. I’ve actually stopped waxing lyrical about Python, and instead I’ve been going on about the innards of BBC BASIC V. I promised that I’d talk a bit about the old programs I had discovered and decoded using the BBC BASIC detokeniser.
To be honest, the only program I was interested in looking at was IRClient — an IRC client I had written for the Archimedes while at University. IRClient was a shareware program which kept me in beers during my days at Exeter Uni. Like many IRC clients, IRClient was fully scriptable. Back in those days I was far too big-headed to consider using someone else’s scripting language; so I devised my own — IRBasic.
I’ve just been looking through some of the source code, and two things strike me. One, that the
interpreter is an absolute mess and it’s impossible to imagine how I wrote it — pure ARM assembler
all the way through; stupendous label names (e.g.
and hard-to-fathom error messages (“Worm tablets at line 6780”)1 to name but a few.
Secondly, the language itself was actually pretty good. Good enough anyway for someone to notice it tucked away unannounced in a “Scripts” directory and then set about writing their own IRClient extensions. That somebody was the rather talented Justin Fletcher (aka Gerph) — a great friendship sprung up between us over that. Justin was able to write an integrated web browser, FTP client and email reader amongst other things — hats off to his reverse engineering skills! Interestingly, this makes IRClient an example of Zawinski’s Law of Software Envelopment — “Every program attempts to expand until it can read mail. Those programs which cannot so expand are replaced by ones which can.”
So, for a quick taster of IRBasic, let’s define a class2. Classes are semi-dynamic inasmuch as they’re defined dynamically, and can be modified so long as there’s no active instance of a class.
Class_BTree = FNRegisterClass("BTree") PROCAddField(Class_BTree,"data") PROCAddField(Class_BTree,"less") PROCAddField(Class_BTree,"more") PROCAddField(Class_BTree,"compare")
As you can see, classes are defined using functions and procedure calls. The Class_BTree is then a “handle” to the metadata of a class, and an instance can be created and used via code like:
tree = NEW Class_BTree PROCtree.Add("test")
Method calls are specially named procedures. For a class
XX, a method call of
YY on an instance
XX is equivalent to calling
XX_YY — with the exception that within
XX_YY there’s a magic “this”
@. There’s also a constructor
XX_Construct and destrutor
XX_Destroy, for example:
DEF PROCBTree_Construct @.compare = FNnewString("BTree_CompareNumbers") ENDPROC
As mentioned above, IRBasic is garbage collected; so there’s no need to explicitly free any object. In fact, IRBasic reference counts every object and then also has a mark/sweep garbage collector to free circular dependencies.
Functions can be overloaded too. If a function with the same name as another is defined, the most recently-defined
function will be called. However, that function may call its “parent” function, with a call to
used this facility extensively to allow user-defined overloads on core functionality.
Overall, I was pretty impressed with how sophisticated IRBasic was. However, I do remember one bad thing about it — it was incredibly slow, about 4–5 times slower than vanilla BBC BASIC. Nevertheless, it was a fun project, and it was really quite interesting to take a look at my ten-year-old code again!