<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>TASM on The Last Psion</title><link>https://thelastpsion.com/tags/tasm/</link><description>Recent content in TASM on The Last Psion</description><generator>Hugo</generator><language>en-gb</language><lastBuildDate>Sun, 12 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thelastpsion.com/tags/tasm/index.xml" rel="self" type="application/rss+xml"/><item><title>Make It Right - Next Steps With CTRAN</title><link>https://thelastpsion.com/posts/make-it-right-next-steps-with-ctran/</link><pubDate>Sun, 12 Jul 2026 00:00:00 0000</pubDate><guid>https://thelastpsion.com/posts/make-it-right-next-steps-with-ctran/</guid><description>&lt;p&gt;Let&amp;rsquo;s start with a quick recap for those of you who are just tuning in (and for those who have been tuned in for a while but are likely very lost):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the late 80s, Psion developed their own message-passing Object Oriented C dialect with its own markup language. They did this because Psion be Psion-ing. This is a recurring theme.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CTRAN.EXE&lt;/code&gt;, a 16-bit DOS app, is Psion&amp;rsquo;s OO preprocessor. It takes class declaration files using this OO markup language (called &amp;ldquo;category files&amp;rdquo; by no one but Psion &amp;ndash; see the previous point) and translates them into C and Turbo Assembler code.&lt;/li&gt;
&lt;li&gt;The C generator in &lt;code&gt;CTRAN.EXE&lt;/code&gt; is rudimentary but very reliable.&lt;/li&gt;
&lt;li&gt;The TASM generator is, shall we say, less optimal. There are bugs. Sometimes it crashes. I&amp;rsquo;m convinced no one actually used it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s an example category file. If you&amp;rsquo;ve written parsers before, you&amp;rsquo;ll enjoy trying to wrap your head around this format!&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;A demonstration cat file
IMAGE demo

! External reference to OLIB library
EXTERNAL olib

INCLUDE p_std.h
INCLUDE p_object.h
INCLUDE varray.g required for knowledge of VAFLAT

CLASS dummy root the class name and its superclass
Dummy class definition,
as an illustration only
 { Methods follow...
 REPLACE destroy free buffer and supersend
 ADD dm_init create VAFLAT component and allocate buffer
 DEFER dm_sub defined by a subclass...
 CONSTANTS auxiliary symbolic constants
 {
 ! for the buffer
 DUMMY_BUF_SIZE 128 allocated buffer size
 ! for the VAFLAT component
 DUMMY_GRAN 16
 }
 TYPES contains auxiliary structs
 {
 typedef struct /* comments here are exceptional */
 {
 TEXT *buf hello; pointer to allocated buffer
 UWORD len;
 DOUBLE stringthing[Z_TEST];
 } DUMMY_BUF;
 }
 PROPERTY 1 Everything after the &amp;#34;1&amp;#34; on this line is a comment, because CTRAN counts tokens. Psion said this is a &amp;#34;feature&amp;#34;.
 {
 PR_VAFLAT *array; the component VAFLAT instance
 DUMMY_BUF buffer;
 }
 }
 
CLASS sub dummy
Subclass of dummy
 {
 REPLACE dm_sub ..so that&amp;#39;s what it does
 }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At the beginning of 2024, after ragequitting the development of a new EPOC16 word processor because of choices Psion made in its OO implementation, I decided to recreate &lt;code&gt;CTRAN.EXE&lt;/code&gt; for modern OSes &amp;ndash; Linux, *BSD, Haiku, macOS, even Windows&amp;hellip; I also wanted a drop-in replacement for the original DOS executable. I chose Free Pascal, because it&amp;rsquo;s highly portable, including having cross-compiler that targets 32-bit DOS. Plus, I like the language, and Object Pascal feels very era-appropriate.&lt;/p&gt;
&lt;p&gt;Fast forward to today. My new CTRAN works at least as well as the original, running on every OS I wanted it to and fixing a lot of the issues with Psion&amp;rsquo;s CTRAN that caused my initial ragequit. I completed the first 90% back in June 2024. This was the &amp;ldquo;make it work&amp;rdquo; phase.&lt;/p&gt;
&lt;p&gt;The last 90% is taking waaaaay too long.&lt;/p&gt;
&lt;h2 id="make-it-right"&gt;Make It Right&lt;/h2&gt;
&lt;p&gt;While I have an engineer&amp;rsquo;s mind, I&amp;rsquo;ll be the first to admit that I&amp;rsquo;m not the best programmer in the world. I get stuff done, but it&amp;rsquo;ll take me a while and the code won&amp;rsquo;t necessarily be pretty.&lt;/p&gt;
&lt;p&gt;The &amp;ldquo;make it right&amp;rdquo; phase is where I&amp;rsquo;m really learning things.&lt;/p&gt;
&lt;p&gt;First, I&amp;rsquo;ve gone through the code and added tonnes of &lt;code&gt;TODO&lt;/code&gt; and &lt;code&gt;FIX&lt;/code&gt; comments. If something isn&amp;rsquo;t clear, or if I think I&amp;rsquo;ve missed an edge case, I&amp;rsquo;m noting it down.&lt;/p&gt;
&lt;p&gt;Readability is key. If I can&amp;rsquo;t understand what&amp;rsquo;s going on in my own code two years on, no one else will be able to. A function that&amp;rsquo;s only ever called once but cleans up the code is a worthwhile function.&lt;/p&gt;
&lt;p&gt;Sometimes I find that I&amp;rsquo;ve attacked the same problem from multiple angles at different times. I probably started off thinking I was solving completely different problems and ended up with a few code snippets or functions that do almost the same thing. By cleaning the code up, I&amp;rsquo;m finding these little snippets all over the place that can be further tidied, which then reveals more snippets that can be tidied, etc.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m flooding the code with comments. Well-written code shows the &lt;em&gt;how&lt;/em&gt; but not necessarily the &lt;em&gt;why&lt;/em&gt;. I&amp;rsquo;m trying to explain Psion&amp;rsquo;s choices, or at least why the code has to be this way to match what Psion did. I&amp;rsquo;m also making it clear when I&amp;rsquo;ve taken a different path and why. Every function needs a description. If I can&amp;rsquo;t describe it, I can&amp;rsquo;t test it.&lt;/p&gt;
&lt;p&gt;The aim is to get CTRAN to a place where I can write unit tests. Currently I&amp;rsquo;m only doing manual testing, which needs to change. My plan is to tackle as many &lt;code&gt;TODO&lt;/code&gt;s and &lt;code&gt;FIX&lt;/code&gt;es as possible before refactoring the code into multiple files. Once I&amp;rsquo;ve done that, I&amp;rsquo;ll make a release (0.0.3? 0.1.0?) and tackle the Great Refactor.&lt;/p&gt;
&lt;h2 id="the-past-6-months"&gt;The Past 6 Months&lt;/h2&gt;
&lt;p&gt;If you &lt;a href="https://oldbytes.space/@thelastpsion"&gt;follow me on Mastodon&lt;/a&gt;, you&amp;rsquo;ll know I&amp;rsquo;ve mostly been dealing with questionable programming choices, both my own and Psion&amp;rsquo;s. I&amp;rsquo;ll go into more detail about specific things in future posts. For now, here are some notable moments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Abstract classes:&lt;/strong&gt; In laymans terms, an abstract class is a class with no new methods and no property, they simply set up a structure for child classes to use. Psion CTRAN skips them in some of its output, and now the new CTRAN does too. I spent months trying to work out how to do this in my head, before having the revolutionary idea of &lt;em&gt;writing the problem down&lt;/em&gt;. It took a weekend to get working.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Turbo Assembler generator:&lt;/strong&gt; I&amp;rsquo;m convinced that Psion (Colly Myers?) added TASM generation to &lt;code&gt;CTRAN.EXE&lt;/code&gt; in a rush, went, &amp;ldquo;Yep, that&amp;rsquo;ll do,&amp;rdquo; and never looked at it again. I&amp;rsquo;m also convinced that no one ever used it. I &lt;em&gt;think&lt;/em&gt; my TASM generator now works better than the original, but I don&amp;rsquo;t know 8086 assembly well enough to know for sure. In addition, I haven&amp;rsquo;t yet found a project that uses CTRAN&amp;rsquo;s TASM output, so I&amp;rsquo;ve got no way to test it. I&amp;rsquo;ve often thought about just dropping the &amp;ldquo;feature&amp;rdquo; from the new CTRAN. For now, I&amp;rsquo;m keeping it in but avoiding any work on it. Also, using it displays a massive disclaimer explaining how broken it probably is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tedious but worthwhile code clean-up:&lt;/strong&gt; Adding small helper functions like &lt;code&gt;IsConcrete()&lt;/code&gt; that help with abstract class detection. Caching the results of function that processes a class&amp;rsquo;s methods rather than calling it multiple times. Not passing unnecessary data to functions. Calling functions as early as possible so that there&amp;rsquo;s less unnecessary data to walk through. Most of these won&amp;rsquo;t make a noticeable difference to how fast CTRAN runs on any machine from the past 20 years, but they make the code more efficient and understandable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-future"&gt;The Future&lt;/h2&gt;
&lt;p&gt;This project sits in a multi-level niche. It&amp;rsquo;s a recreation of a little-known tool in a largely forgotten SDK for a long-discontinued operating system on a selection of 16-bit portables from the 90s. But it&amp;rsquo;s a platform I deeply care about for all sorts of reasons, the least of which is nostalgia.&lt;/p&gt;
&lt;p&gt;My next step is to rewrite the rest of the tools in the SDK. There are a few more small apps that handle resource file creation, object manipulation and executable linking. None of them are particularly complicated, but without any source code they&amp;rsquo;ll need to be reverse-engineered manually.&lt;/p&gt;
&lt;p&gt;Eventually I&amp;rsquo;ll tackle the compiler, a project that will inevitably render CTRAN redundant. After all, there&amp;rsquo;ll be no need for a separate preprocessor if the compiler can handle OO code. That doesn&amp;rsquo;t mean CTRAN is a waste of time. It&amp;rsquo;s where I&amp;rsquo;m cutting my teeth, learning how to write better code, not to mention the basics of lexers, parsers, abstract syntax trees, etc.&lt;/p&gt;
&lt;p&gt;At some point I might even use it to write that new word processor.&lt;/p&gt;</description></item></channel></rss>