Dr. Brian Robert Callahan
academic, developer, with an eye towards a brighter techno-social life
All source code for this blog post can be found here.
As a fun afternoon challenge, I decided to write a C program that looked nothing like C. Not necessarily obfuscated, though there is a competition for that if you are so inclined.
No, instead I thought to myself, what if I turned C into an entirely different language, then wrote a program in that language, then used the C compiler to compile the program. That to me sounds like the least-C C program I could write.
Here it is, in all its glory:
#include"cpaint.h" var a, b, c, h, i, l, v, x, y, q, w, p size 65535 , packed n size 13 ꞉integer ; procedure display(r,s,c) ; begin LOOP call A(Z) ; call H(y,x) ; call B(Z) POOL ; y ꞉= r; x ꞉= s; call A(c) ; call H(y,x) ; call B(c) ; call refresh() end ; procedure fill(y,x,c,a) ; begin if(y<0 or y>w-1 or x<0 or x>q-1 or c = a or Z <> a)fill꞉= -1 ; call draw(c) ; call fill(y+1,x,c,a) ; call fill(y-1,x,c,a) ; call fill(y,x-1,c,a) ; call fill(y,x+1,c,a) end ; procedure save(r,s) ; begin i ꞉= 0 ; while(i<13)do begin n[i] ꞉= 0 ; i ꞉= i+1 end ; call move(w>>1,(q>>1)-6) ; call printw("Save: ") ; call echo() ; call getnstr(n,12) ; call noecho() ; call open(n,"w+") ; call writeChar(83) ; call writeChar(w) ; call writeChar(q) ; LOOP call writeChar(Z) POOL ; y ꞉= r; x ꞉= s; call close ; call move(y,x) end ; procedure load(packed ʌ n) ; begin call open(n,"r") ; call check ; LOOP readln(c); call draw(c) POOL ; c ꞉= 0; call close end ; procedure m() ; begin l ꞉= 0 ; v ꞉= 1 ; call A(c) ; call H(0,0) ; call B(c) ; call refresh() ; while(v)do begin read(inp) ; '/':l ꞉= not l ; if(l)call draw(c) ; OK 'k':y ꞉= y-1 ; if(y<0)y ꞉= 0 ; if(l)call draw(c) ; OK 'j':y ꞉= y+1 ; if(y>w-1)y ꞉= w-1 ; if(l)call draw(c) ; OK 'h':x ꞉= x-1 ; if(x<0)x ꞉= 0 ; if(l)call draw(c) ; OK 'l':x ꞉= x+1 ; if(x>q-1)x ꞉= q-1 ; if(l)call draw(c) ; OK ' ':call draw(c) ; OK 'c':c ꞉= c+1 ; if(c = M)c ꞉= 0 ; OK 'd':call draw(15) ; OK 'f':call fill(y,x,c,Z) ; OK 's':call save(y,x) ; OK 'q':v ꞉= 0 ; OK 'v':c ꞉= c-1 ; if(c = N)c ꞉= M-1 ; CALL display(y,x,c) end end ; procedure main(I c,packed ʌ ʌ v) ; begin call start ; call getmaxyx(stdscr,w,q) ; if(w>M)w ꞉= M ;if(q>M)q ꞉= M ; call start_color() ; while(x<M)do begin call init_pair(x,x,x) ; x ꞉= x+1 end ; LOOP call draw(15) POOL ; if(c = 2)call load(v[c-1]) ; call display(0,0,0) ; call m() ; call endwin() end ; call main.
I hear what you're saying: "This is literally not C. It has all the markings of a Pascal language, with the semicolon as statement separator rather than statement terminator, the :=
for assignment, and maybe some Algol with the LOOP .. POOL
syntax." It even has the Pascal-style return assignment where you assign the function a value and that's its return value (see the fill
procedure).
Caught me. I had recently heard that Arthur Whitney, author of the A+, k, and q languages (which are array programming languages like APL and J), would use the C preprocessor to create his own language and then write the implementation of his language in that self-defined language. I decided to try to do the same.
I loosely based my self-defined language off of PL/0, which we wrote a compiler for previously (yes, I know I have to finish the self-hosting blog series; I will finish it).
The hero of this exercise was the fact that the C compilers understand UTF-8 characters as valid characters for identifiers. I use lots of characters that look like ASCII but are in fact not ASCII but nonetheless accepted as valid identifier characters. The C preprocessor happily accepts macros that transform these identifiers into whatever you need them to. You can see the hidden away header file here. Creative use of whitespace helped finish it off.
If you want to see what the C code truly looks like, trying running:
$ cc -E cpaint.c | clang-format | less
For a short afternoon, it was amusing. I probably won't try something like this again. But it was fun to discover some interesting ways to abuse the C preprocessor.
Oh, and if you actually want to use the program, it's a simple terminal paint program.