7.1 KiB
T3X
{ Just discovered this thanks to a friend, WORK IN PROGRESS, MAY HAVE ERRORS etc. ~drummyfish }
T3X is a family of relatively obscure minimalist programming languages similar to Pascal, made by Nils M Holm. There are different versions of the language (dating back to the 90s), distinct mainly by "feature richness" and small polishing over the years, but being very similar in general; most notable is probably T3X/0 (made in 2022), described as a "sweet spot" between minimalism and "practical usability". The code is released under permissive free software licenses, some even under CC0, but sadly some of the formal specifications are proprietary and accessible only after payment. The languages are very well implemented, the body of work is a joy to behold and explore -- even though very strictly speaking these languages aren't the absolute peak of minimalism (some even sport some kind of "simplified OOP") but rather seem like an attempt at remaking an oldschool language in nicest way possible while keeping to some pragmatic and practical choices, still compared to anything modern they are super minimal; C definitely looks like a pile of bloat compared to T3X languages. For more details see the author's website at https://t3x.org/t3x/index.html.
The languages are very cool but their implementation is probably what's even more notable here: T3X/0 is self hosted in about 4 thousand lines { Doing wc -l *.t library/*.t
. ~drummyfish }, bootstrappable and extremely portable (so far lists e.g. generic Unix, freeBSD, mac, DOS, CP/M, 386, x86, ARM), allowing cross compilation basically on every supported platform to any other etc. This is an example of how software should be written.
The languages evolved from early (1995) experimental languages named T_1
and T_2
into a big tree of languages and compilers. The most notable ones are currently probably these:
- T3X (1997): Some kind of stable language emerged from the initial languages.
- T3X9 (2017): T3X subset, smallest (around 1600 LOC of self hosted code) but (looks like) not extremely portable because directly targets 386 architecture.
- T3X/Z (2019): Port of T3X9 to Z80 architecture.
- T3X/86 (2021): Port of T3X9 to x86 DOS.
- T3Xr7 (2003): A little more bloated.
- T3X/0 (2022): Probably the most notable one, something between T3X9 and T3Xr7. Highly portable.
Worthy of mention is also so called Tcode, a bytecode and virtual machine (called TCVM) that the languages use. They also compile to native binary programs, but the bytecode also allows for interpreting the programs, decouples the compiler frontend and backends etc.
The author, Nils M Holm, is a Buddhist (according to his website a "pragmatic" one) minimalist programmer living in Germany, probably of older age (considering he keeps talking about programming in the 80s and was making own languages in the 90s), who has published an impressive number of books (sadly proprietary) on the topic of minimalist programming, compilers, Lisp etc., sharing some views with LRS (expressing sadness about what computer science has evolved into since the 80s, that "hackers turned into entrepreneurs" and so on).
LRS is always very happy to see people strive for simplicity and we applaud the author's passion and incredible effort over several decades whose fruit is now very helpful to the entire world. A few words of criticism could be stated of course, like always, for example that the language seems to go for unnecessary features such as modules or even objects -- there is no need to implement modules that enforce encapsulation and allow dot syntax like for example t3x.write
if we can achieve the same thing by simply writing a library with prefixed functions, e.g. t3x_write
(while keeping private members further prefixed with _
, like _t3x_internalvariable
). Some syntax elements, like do ... end
instead of plain curly brackets (which are objectively better) seem to be perhaps a little driven by nostalgia. From ultraminimalist point of view the language is actually quite feature rich, which is fine, but then suddenly some really useful features that would be expected at this level, such as a number printing function, seem to be missing. Some functions and constructs are a little tricky and not self-documenting, for example the for loop just takes 2 arguments and it's not clear what they mean, the upper bound behaves like traditional C for loop, i.e. iterating as long as the variable is BELOW (and NOT equal) to the bound, but whereas in C this is clear by the presence of the <
operator, here we are left guessing, and one would probably expect <=
is actually implied { Before looking it up I actually even considered that it may say the NUMBER of iterations. ~drummyfish }. Also the built-in printing function is a bit awkward, first taking file descriptor, then the string, and then the length of the string (which itself is zero terminated). In any case the author will probably keep improving the language as he has been for a long time, so we may very likely expect his work to get more and more polished.
T3X/0: The Language
Here is a summary of T3X/0, the language we find most interesting.
It is vaguely similar to Pascal, imperative, procedural, case insensitive, may be both compiled and interpreted (includes bytecode). Features include procedures, vectors, recursion, modules etc. There are a few simple data types such as integers, vectors, byte vectors and strings (which are actually just vectors of integers).
As a code example here is our standardized divisor tree algorithm implemented in T3X/0:
use t3x: t; ! include the core module
printChar(c) do
t.write(1,@c,1);
end
printNum(x) do
if (x > 99)
printChar('0' + x / 100);
if (x > 9)
printChar('0' + (x / 10) mod 10);
printChar('0' + x mod 10);
end
! recursive function, prints divisor tree of x
printDivisorTree(x) do
var a, b, i;
a := -1;
b := -1;
for (i = 2,x / 2 + 1) ! find two closest divisors
if (x mod i = 0) do
a := i;
b := x / i;
if (b <= a)
leave;
end
printChar('(');
ie (a > 1) do
printDivisorTree(a);
printChar(' ');
printNum(x);
printChar(' ');
printDivisorTree(b);
end else
printNum(x);
printChar(')');
end
do var str::4, n, i, c; ! main program
while (%1) do ! main loop, read numbers from the user
t.write(1,"enter a number: ",16);
t.read(0,str,3);
n := 0;
i := 0;
while (str::i \= 0 /\ str::i \= '\n') do ! convert str to num
c := str::i - '0';
if (c < 0 \/ c > 9)
halt 0;
n := n * 10 + c;
i := i + 1;
end
printDivisorTree(n);
printChar('\n');
end
end