Letterfuck

From Esolang
Jump to navigation Jump to search

Letterfuck

Letterfuck (LF) is an esoteric programming language inspired by Brainfuck and Piet, but using letters as commands. LF combines a memory tray similar to Brainfuck with a stack like Piet. Programs are sequences of letters, with the differences between letters encoding commands and repeated letters forming blocks.

Overview

LF programs use a memory tray (array of cells) and a stack (LIFO). Each command is represented by the change in letters.
You read the LF bytecode in adjacent pairs of blocks. - Syntax for each pair: aAbB

  • a is a parameter for the current command
  • b is a parameter for the next command
  • A,B are letters from A-Z

- Opcode = index(B) - index(A) if B > A, or 26 + index(B) - index(A) if B < A.
- Repeated letters form a block, with size representing the parameter for some commands.
- Example: AAAB does command 1, parameter 3
One crucial rule: The last block for this command is the first block for the next command. So aAbBcC has 2 commands: aAbB (command B-A, param a) and bBcC (command C-B, param b). You can look at the examples below to know more.

Commands

Opcode Command Param Description
1 IDXINC VAL Increase memory index: index += VAL
2 IDXDEC VAL Decrease memory index: index -= VAL
3 INC VAL Add VAL to current cell: tray[index] += VAL
4 DEC VAL Subtract VAL from current cell: tray[index] -= VAL
5 IN(CHAR) NONE Input a character: tray[index] = ASCII(input_char()). Identical to Brainfuck's ",". EOF: 0
6 ZERO (ZZ) NONE Next command receives 0 as parameter. If its block size is above 1, use ZZ (zero-zero) as a parameter instead
7 IN(NUM) NONE Input a number: tray[index] = input_number()
8 OUT(CHAR) CELL Output ASCII character: system.write(tray[index]). Also recieves literal string. See LF Programs to know more.
9 OUT(NUM) CELL Output number: system.write(tray[index])
10 NEG VAL Negation: NEG a = -a; if a=ZZ → 1
11 STARTLOOP VAL Loop VAL times
12 ENDLOOP NONE End loop
13 EQ VAL Compare top of stack with VAL: 1 if equal, -1 if not
14 BRK VAL Break out of WHILE loops. Executes the next command after the nearest ENDWHILE if there are no parameters. Otherwise, executes the next command after the VAL-th nearest ENDWHILE.
15 WHILE VAL While VAL=1, repeat loop
16 ENDWHILE NONE End while loop
17 PUSH CELL Push cell to stack, reset cell. If it was used with param ZZ, do not reset cell
18 POP STACK Pop stack to cell. If it was used with param ZZ, turn to PEEK (pastes the top of stack to cell without removing it from stack)
19 CMP STACK Pop the 2 top stack values and compare them (Top vs Second). Push 0 if Top<Second, 1 if Top>Second, 2 if Top=Second
20 DUP STACK Duplicate top of stack
21 SUB STACK Pops Top and Second, subtract them (Second-Top), pushes the result back
22 ADD STACK Pops Top and Second, add them (Top+Second), pushes the result back
23 MUL STACK Pops Top and Second, multiply them (Top*Second), pushes the result back
24 DIV STACK Pops Top and Second, divide them and floor the result (Second/Top), pushes the result back
25 END NONE End program

LFASM

LF is hard to read, so there's a helper syntax:


  • LFASM (LF Assembly):

Uses mnemonics for easier coding. 9A8LOAIH →

STARTLOOP, 9 // 9A8L
INC, 8       // 8LO
ENDLOOP      // OA
OUT(CHAR)    // AI
END          // IH

LF Programs

If any of you understands LF syntax, you can try writing a program here! I'd apperciate it, and even more if you manage to write a compiler for this thing.

LF Programs

Hello World!

out(char), "Hello World!"
end

LF: A"Hello World!"IH

Cat program

WHILE, 1
  IN(CHAR)
  PUSH
  STARTLOOP, EQ, 0
    BRK
  ENDLOOP
  POP
  OUT(CHAR)
ENDWHILE
END

LF: APULREPDPHPFE

ASCII Printer

idxdec, 1
in(num)
while, 1
push
startloop, eq, 0
brk
endloop
pop
dec, 1
idxinc, 1
inc, 1
out(char)
idxdec, 1
endwhile
end

LF: Coming soon
This prints the ascii characters from 1 to N, with N being the input. Supports any N, even N > 127. Set stack cap to 1 and tray size to 3 on the compiler for it to be faster.

FizzBuzz

idxinc, 3
inc, 10
idxdec, 3
startloop, 100
while, 1
inc, 1
idxinc, 1
inc, 3
idxdec, 1
push, zz
idxinc, 1
push, zz
div
push, zz
mul
idxdec, 1
push, zz
cmp
startloop, eq, 2
out(char), "Fizz"
idxdec, 1
inc, 1
idxinc, 1
endloop
idxinc, 1
inc, 2
idxdec, 1
push, zz
idxinc, 1
push, zz
div
push, zz
mul
idxdec, 1
push, zz
cmp
startloop, eq, 2
out(char), "Buzz"
idxdec, 1
push
idxinc, 1
brk
endloop
idxdec, 1
push
startloop, eq, 1
idxinc, 1
brk
endloop
idxinc, 1
out(num)
brk
endwhile
idxinc, 3
out(char)
idxdec, 2
push
idxdec, 1
endloop
end

LF: 3A10B3E100GRGJ3KNP2UMN2TKT2OFCE2KB2UHS"Fizz"ACFGS2TWY2EVW2CTR2XOLN2TK2DQB"Buzz"JLCDRDFWJUVJVWFT3JK2SULNZY

Prime tester

in(num)
push, zz
idxinc, 3
inc, 1
push
cmp
startloop, neg, eq, 0
out(char), "Not a prime."
end
endloop
idxdec, 3
push, zz
idxinc, 3
inc, 2
push
cmp
startloop, eq, 2
out(char), "A prime."
end
endloop
idxdec, 3
while, 1
push, zz
idxinc, 2
push, zz
dup       
mul
cmp        
startloop, eq, 1
brk
endloop
startloop, eq, 2
brk
endloop
inc, 1
idxdec, 2
endwhile
idxdec, 1
inc, 1
while, 1
inc, 1
idxdec, 1
push, zz
idxinc, 1
push, zz
div
push, zz
mul
idxdec, 1
push, zz
cmp
startloop, eq, 2
out(char), "Not a prime."
brk
endloop
idxinc, 2
push
startloop, eq, 2
out(char), "A prime."
brk
endloop
pop
dec, 1
idxdec, 1
endwhile
end

LF: Coming soon (Note: In the compiler, for some edge cases, run with the normal RUN button to avoid bugs.)
Tip: Set stack cap to 3 and tray size to 4 for this to reach its maximum speed.

Prime printer

idxdec, 1
out(char), "Primes:\n"
in(num)
push, zz
idxdec, 1
inc, 1
push
idxinc, 1
cmp
startloop, neg, eq, 0
out(char), "None!"
end
endloop
push, zz
idxdec, 1
inc, 2
push, zz
idxinc, 1
cmp
startloop, eq, 2
out(char), "2"
end
endloop
push, zz
idxdec, 1
push
div
idxinc, 1
pop
idxinc, 1
inc, 1
out(char), "2\n"
while, 1
inc, 2
push, zz
while, 1
push, zz
idxinc, 2
push, zz
dup       
mul
cmp        
startloop, neg, eq, 0
brk
endloop
inc, 1
idxdec, 2
endwhile
idxdec, 1
inc, 1
while, 1
inc, 1
idxdec, 1
push, zz
idxinc, 1
push, zz
div
push, zz
mul
idxdec, 1
push, zz
cmp
startloop, eq, 2
idxinc, 3
push
idxdec, 3
brk
endloop
idxinc, 2
push
startloop, eq, 2
idxinc, 1
inc, 1
push
idxdec, 3
brk
endloop
pop
dec, 1
idxdec, 1
endwhile
startloop, eq, 1
out(num)
out(char), "\n"
endloop
idxdec, 1
push
startloop, eq, 1
brk
endloop
pop
dec, 1
idxinc, 2
push
idxdec, 1
endwhile

LF: Coming soon
Prints all prime numbers from 1 to N+1 if N is even, else print all prime number from 1 to N. Recieves N as an input.
Tip: set tray size to 5, stack cap to 3 for maximum speed.

Decimal to Base N (now with hexadecimal support)

dec, 999
push
in(num)
push, zz
idxinc, 1
in(num)
push, zz
idxdec, 1
while, 1
// divmod
idxinc, 1
pop
idxdec, 1
pop
push, zz
idxinc, 1
push, zz
div
idxdec, 1
push, zz
idxinc, 1
push, zz
idxinc, 3
// mod
pop
idxinc, 1
pop, zz
idxdec, 1
push, zz
div
push
mul
idxinc, 1
push
sub
dec, 1
push
mul
idxdec, 3
pop
idxdec, 2
pop
idxinc, 2
push
idxdec, 2
push, zz
startloop, eq, 0
pop
brk
endloop
idxinc, 1
push, zz
idxdec, 1
endwhile
while, 1
while, 1
startloop, eq, -999
brk
endloop
startloop, eq, 10
out(char), "A"
pop
brk
endloop
startloop, eq, 11
out(char), "B"
pop
brk
endloop
startloop, eq, 12
out(char), "C"
pop
brk
endloop
startloop, eq, 13
out(char), "D"
pop
brk
endloop
startloop, eq, 14
out(char), "E"
pop
brk
endloop
startloop, eq, 15
out(char), "F"
pop
brk
endloop
pop
out(num)
endwhile
endwhile
end

LF: Coming soon.
Recieves a decimal number d and prints out its base-n representation. d is the first input, n is the second input.
Tip: Set tray size to 5. For stack size: when stack size = k and n = p (base p), the maximum number you can convert is p^(k-3) - 1. Exceed this limit and you might hang the compiler.

LF Gadgets

Gadgets for convenience. Pre-execution and post-execution included.

Modulo

// Pre: stack contains: [a, b] (bottom to top). Pointer at cell n. 
// Cell n and n+1 must be unused as this will zero both cells.
// Also, initially, both cells have to be 0.
pop
idxinc, 1
pop, zz
idxdec, 1
push, zz
div
push
mul
idxinc, 1
push
sub
dec, 1
push
mul
idxdec, 1
// Post: stack contains: [a%b]. Pointer stays at cell n. 
// Minimum stack cap: 2.
// Minimum tray size: 2.

DivMod (Division + Modulo)

// Pre: stack contains [a, b] (bottom to top). Pointer at cell n.
// Cell n and n+1 must be unused. Cell n will be set to a and cell n+1 will be set to b.
idxinc, 1
pop
idxdec, 1
pop
push, zz
idxinc, 1
push, zz
div
idxdec,1
push, zz
idxinc,1
push, zz
idxinc, 1
pop
idxinc, 1
pop, zz
idxdec, 1
push, zz
div
push
mul
idxinc, 1
push
sub
dec, 1
push
mul
idxdec, 3
// Post: stack contains: [floor(a/b), a%b] (bottom to top). Pointer stays at cell n.

Implementations

The official compiler for LF is live on GitHub: https://alphamain407-max.github.io/LF_Compiler/
Note (00:57 Jan 18 2026): The BRK with param is not in the compiler yet. Will implement it tomorrow.
Note (18:49 Jan 18 2026): v2.9.7 features Stack Cap. Go try it out! Also, BRK, VAL is implemented.
Note (01:40 Jan 20 2026): The Base N thing really took me a while. NEG doesn't work with STARTLOOP, gonna fix it later!

See also