An esolang that uses letters, not symbols
33 is an esolang created to use letter characters instead of the strange symbols other esolangs use. Yes, there are some symbols, such as [] for loops, {} for functions, and “” and ‘’ for strings, but they’re more standard than the stuff some other esolangs use. There are 33 distinct letter commands in the language.
Get the latest release from the releases page of this repository. Put it on your $PATH if need be.
After installing the interpreter, execute it with -f <filename>
to execute a file. Adding the -d
flag will show a debugger.
The debugger allows you to step through the program, one instruction at a time, and see the internal values of the registers. It prints the values stored in the accumulator, counter, source string, destination string, and mutable list (in that order).
There are 3 output commands:
p
: Prints the string in the source string register to standard outputo
: Prints the value in the accumulator to standard outputi
: Prints a newlineThere are three input commands:
P
: Sets the accumulator to the value of the next character read from stdinO
: Sets the accumulator to the next integer read from stdinI
: Sets the destination string to the next line read from stdinThere are 2 integer memory registers, a general integer memory, two string memory registers, and 2 list memory registers.
Of the two integer memory registers, the accumulator is the one that can have mathematical operations performed on it, the one that can be checked conditionally, and the one that can be read from/written to general memory. The counter is the one that can have values put into it directly.
The general memory is accessed via strings.
0-9
: Multiplies the counter by 10, then adds itself. For example: 50coc7co
will output 50507
a
: Adds the counter to the accumulatorm
: Subtracts the counter from the accumulatorx
: Multiplies the accumulator by the counterd
: Divides the accumulator by the counterr
: Sets the accumulator to the remainder of the accumulator divided by the counterz
: Sets the counter to 0c
: Swaps the counter and the accumulators
: Stores the accumulator’s current value at the location in the destination string registerl
: Loads the value in memory referenced by the source string register into the accumulatorThere are two string registers, a source, and a destination. Their functions are described in other sections. The source is set by
enclosing a string in double quotes (""
), and the destination by single quotes (''
).
t
: Swaps the source string and the destination stringj
: Sets the accumulator to the value of a character in the source string, referenced by the counterk
: Sets a character in the destination string, referenced by the counter, to the character represented by the value in the accumulator.
).e
: Appends the source string to the destination stringThere are two list registers. One that you can perform operations on, and one for simply storing a second list. The list is initially filled in with argv
b
: Sets the destination string to a string in the mutable list, specified by the counterf
: Sets a value in the mutable list, specified by the counter, to the source stringu
: Swaps the mutable and backup listsv
: Appends the backup list to the mutable listw
: Sets the accumulator to the length of the mutable listy
: Appends the source string to the mutable listZ
: Clears the mutable listConditional operators skip the next operation if the condition is not met.
n
: Performs the next operation if the accumulator is equal to 0.N
: Performs the next operation if the accumulator is not equal to 0.g
: Performs the next operation if the accumulator is greater than 0.G
: Performs the next operation if the accumulator is not greater than 0 (i.e. less than or equal to 0).h
: Performs the next operation if the accumulator is less than 0.H
: Performs the next operation if the accumulator is not less than 0 (i.e. greater than or equal to 0).Functions use the string registers to create and call. The destination register is queried when creating a function, and the source
when calling. Creating a function is as simple as setting the destination register, then enclosing a block of code in braces, for
example: 'Print'{"Hello, World!"p}
.
To call a function, you must set the source register, then perform the q
operation. Following on from the previous example, that
would be: "Print"q
.
Register values are kept when changing stack frames. This means you can do stuff like this:
{"Hello"p}'Hello'{", "p}', '{"World"p}'World'{"!"pi}qqqq
to print “Hello, World!”
Loops are notated using square brackets ([]
). When a closing bracket is found, the code jumps back to the matching opening
bracket if the accumulator is not 0. For example: This code 10az1[oim]"Done."pi
will count down from 10 until it reaches 1,
then it will print “Done.”. To make it count down until it reaches 0, this code would be used: 11az1[moi]"Done."pi
.
When the program reaches the end of input, the interpreter terminates. No printing is done after this. The program can be
terminated early with the @
operator.
a
: Adds the counter to the accumulatorb
: Sets the destination string to a string in the mutable list, specified by the counterc
: Swaps the counter and the accumulatord
: Divides the accumulator by the countere
: Appends the source string to the destination stringf
: Sets a value in the mutable list, specified by the counter, to the source stringg
: Performs the next operation if the accumulator is greater than 0.G
: Performs the next operation if the accumulator is not greater than 0.h
: Performs the next operation if the accumulator is less than 0.H
: Performs the next operation if the accumulator is not less than 0.i
: Prints a newline to standard outputI
: Sets the destination string to the next line read from stdinj
: Sets the accumulator to the value of a character in the source string, referenced by the counterk
: Sets a character in the destination string, referenced by the counter, to the character represented by the value in the accumulator.l
: Loads the value in memory referenced by the source string register into the accumulatorm
: Subtracts the counter from the accumulatorn
: Performs the next operation if the accumulator is equal to 0.N
: Performs the next operation if the accumulator is not equal to 0.o
: Prints the value of the accumulator to standard outputO
: Sets the accumulator to the next integer inputp
: Prints the string in the source string register to standard outputP
: Sets the accumulator to the value of the next character read from stdinq
: Calls the function from the source stringr
: Divides the accumulator by the counter but keeps the remainders
: Stores the value of the accumulator in memory referenced by the destination stringt
: Swaps the source and destination stringsu
: Swaps the mutable and backup listsv
: Appends the backup list to the mutable listw
: Sets the accumulator to the length of the mutable listx
: Multiplies the accumulator by the countery
: Appends the source string to the mutable listz
: Sets the counter to 0Z
: Clears the mutable list