硬!!!
- The title of this article is also called HARD!!!.
硬!!! is an esoteric programming language designed by PSTF.
It is designed to let the programming to be hard and verbose(hard can both be translated to “困难” or “硬” in Chinese).
Overview
- Only one data manipulation primitive: swap a b exchanges the values of two variables.
- No assignment – you cannot set a variable to a value. You can only swap its contents with another variable.
- Variables are named by integers (e.g., 0, 1, 2, …). All variables are global and start at 0.
- Two arithmetic operations: inc a and dec a (increment/decrement variable a by 1). That’s it. No add, mul, or mov.
Control flow
- ifz a – skip the next instruction if variable a is zero.
- jump label – unconditional jump.
- label: – a target for jumps.
- whilenz a – jump over nearest endwhile if a is zero. This is added after 2.0 version.
- endwhile – jump back to nearest whilenz a if a is not zero. This is added after 2.0 version.
Functions
- gosub label – call a function (pushes return address onto a hidden call stack).
- return – return to the caller.
- Functions have no parameters and no local state – they operate directly on the global variable pool.
I/O
- read a – read an integer from stdin into variable a.
- write a – write variable a to stdout as an integer.
- readchar a – read a Unicode character from stdin into variable a.
- writechar a – write variable a to stdout as a Unicode character.
Why is it hard?
- No assignment – To set variable x to 42, you need a variable that already contains 42, then swap. To create a constant, you must increment from zero 42 times. To copy a value, you need a temporary variable and a three‑way swap dance.
- No expressions – Adding two numbers requires a loop that decrements one and increments another. Multiplying is a nested loop. Comparing two values means repeatedly decrementing both until one hits zero – but you lose the original values in the process.
- Everything is global – Functions cannot have private scratch space. You must manually save and restore variables around calls using more swaps and a dedicated “scratch” variable (which you also have to manage).
- Conditionals only skip one instruction – This forces you to write ifz a followed by a jump to skip a block, making control flow verbose and error‑prone.
Example
r = a + b
Suppose we want to compute r = a + b, where a, b, and r are variables. We need a temporary t. We also need a zero variable (say z) that never changes.
; Initialize: assume z is forever 0 ; Copy a into r using a temporary t swap a t swap t r swap a t ; now r = a, t = 0, a restored ; Loop: while b != 0, increment r and decrement b label loop ifz b jump end inc r dec b jump loop label end ; Done – r contains a+b, b is 0, t and z unchanged
That’s 10 instructions for a simple addition. Multiplication would require nested loops and even more temporary juggling.
x = y
Inspired from Brainfuck.
whilenz temp0 dec temp0 endwhile whilenz x dec x endwhile ; Now temp0 is zero, x is ready whilenz y inc x inc temp0 dec y endwhile swap temp0 y ; Done – x contains y, temp0 restored, y kept
Computational Class
硬!!! can simulate a two‑counter Minsky machine:
- Counters are variables.
- Increment/decrement are inc and dec.
- Zero test is ifz followed by a jump.
- Functions (gosub/return) provide subroutine calls, but even without them, the unconditional jump and conditional skip give enough power to implement a Minsky machine with a single loop and a state variable. Hence 硬!!! is Turing‑complete.
After 2.0 version, 硬!!! supported while(x){code} loop, making 硬!!! a quasi-brainfuck-derivative which just directly replace > and < by "cell indexes".
Complex Examples
A+B Problem
gosub read_two gosub add gosub write_result halt label read_two read 0 ; first number into var0 read 1 ; second number into var1 return label add ; assume var0 = a, var1 = b, result in var2 ; ... (the addition code above, using var2 as r, var3 as t, var4 as z) ; after addition, var2 = a+b, var1 = 0 return label write_result write 2 return
Hello, world!
Warning: If this program is really written using the standard version of 硬!!!, it will result in a very long pile of shitty code (especially for the 😀 character, because it corresponds to 128,512 inc instructions).
Here I used Lvl.1-ASM-like code instead of real code.
; ------------------------------------------------------------ ; 硬!!! program: Hello, world! ; Uses variables: ; 0 = permanent zero (never changed) ; 10 = 'H' (72) ; 11 = 'e' (101) ; 12 = 'l' (108) ; 13 = 'l' (108) ; 14 = 'o' (111) ; 15 = ' ' (32) ; 16 = 'w' (119) ; 17 = 'o' (111) ; 18 = 'r' (114) ; 19 = 'l' (108) ; 20 = 'd' (100) ; 21 = '!' (33) ; 22 = '\n' (10) ; ------------------------------------------------------------ ; ---- Build 'H' (72) in var10 ---- add 10 72 putc 10 ; ---- Build 'e' (101) in var11 ---- add 11 101 putc 11 ; ---- Build 'l' (108) in var12 ---- add 12 108 putc 12 ; ---- Build second 'l' in var13 ---- add 13 108 putc 13 ; ---- Build 'o' (111) in var14 ---- add 14 111 putc 14 ; ---- Build space (32) in var15 ---- add 15 31 putc 15 ; ---- Build 'w' (119) in var16 ---- add 16 119 putc 16 ; ---- Build 'o' (111) in var17 ---- add 17 111 putc 17 ; ---- Build 'r' (114) in var18 ---- add 18 114 putc 18 ; ---- Build 'l' (108) in var19 ---- add 19 108 putc 19 ; ---- Build 'd' (100) in var20 ---- add 20 100 putc 20 ; ---- Build '!' (33) in var21 ---- add 21 33 putc 21 ; ---- Build newline (10) in var22 ---- add 22 10 putc 22 halt
Now, 硬!!! remains a masterpiece of anti‑usability, now with Unicode support to make international suffering possible.