Rings
Paradigm(s) | imperative |
---|---|
Designed by | User:Ardemit |
Appeared in | 2022 |
Memory system | Cell-based |
Dimensions | one-dimensional |
Computational class | Linear-bounded automaton |
Major implementations | Original |
File extension(s) | .rn |
Rings is a simple programming language designed around the idea of working with rotating memory strips. The language was originally designed to compete in the June 2022 Esolang Discord competition.
Language overview
The language revolves around turnable rings of varying length (or capacity if you want to picture them as all being the same size). Each ring can store up to 255 unsigned 8 bit integers (but cannot be zero-length) and can rotate counter-clockwise up to 255 steps at once (rotary right shift). All operations working with values stored on the rings only use the currently selected value, usually represented on a state diagram as being the leftmost value on the ring. Imagine looking at a vertical rod, on which the rings are stacked. You are the interpreter and can only see the values in front of you. If you want to access other ones, you need to rotate the rings around. There can be at most 256 rings, indexed 0-255.
Table of instructions
- Arguments are either a byte (B) or a label (L)
Instruction | Opcode | Arguments | Description |
---|---|---|---|
mkr | 0x0 | B | Creates a new ring. The argument specifies the length. |
put | 0x1 | B B | The first argument specifies a ring, the second a literal value, that will be put onto said ring. |
rot | 0x2 | B B | The first argument specifies a ring, the second a literal value, that will tell the ring how many steps to rotate. |
swp | 0x3 | B B | Both arguments represent rings. The values on these rings will be swapped. |
inp | 0x4 | B | Reads a value from stdin and puts it onto the ring specified by the argument. |
out | 0x5 | B | Writes the value on the ring specified by the argument to stdout. |
err | 0x6 | B | Writes the value on the ring specified by the argument to stderr. |
add | 0x7 | B B B | All arguments represent rings. Add the values on the first two rings and put them onto the third. (A+B=C) |
sub | 0x8 | B B B | All arguments represent rings. Subtract the second ring's value from the first ring's value and put the result onto the third. (A-B=C) |
mul | 0x9 | B B B | All arguments represent rings. Multiply the values of the first two rings and put the result onto the third. (A*B=C) |
div | 0xA | B B B | All arguments represent rings. Divide the first ring's value by the second ring's value and put the result onto the third. (A/B=C) |
jmp | 0xB | L | The argument is a label, that the interpreter unconditionally jumps to. |
jeq | 0xC | B B L | The first two arguments represent rings, the third is a label. If the ring's values are equal, jump to the label. (A=B) |
jgt | 0xD | B B L | The first two arguments represent rings, the third is a label. If the first ring's value is greater than the second ring's, jump to the label. (A>B) |
jlt | 0xE | B B L | The first two arguments represent rings, the third is a label. If the first ring's value is less than the second ring's, jump to the label. (A<B) |
hlt | 0xF | B | Halts the program, with the argument representing an exit code literal. |
Source code structure
In Rings, each line corresponds to a single instruction. Leading and trailing whitespaces are ignored, but arguments must be separated by a single regular space (U+0020). In addition to the instructions in the table above, there is a special instruction that declares labels, that act as instruction pointers in jump instructions.
Labels are defined using the :
(colon) character, followed by the name of the label. Names must not contain any whitespaces, so :lbl_test
is a valid label, but : lbl_test
or :lbl test
are not. Jump instructions are then passed the label names (including the colon).
Literal values can be defined using prefixes. Hexadecimal values can use both uppercase and lowercase characters.
System | Prefix | Example | Decimal value |
---|---|---|---|
Decimal | 182 | 182 | |
Hexadecimal | 0x | 0xB6 | 182 |
Hexadecimal | 0X | 0XB6 | 182 |
Octal | 0 | 0266 | 182 |
Binary | 0b | 0b10110110 | 182 |
Any line beginning with the #
character is considered a comment and is ignored.
A short Rings example program using all the rules described in this section:
# Declare a ring for no reason and put 241 on it mkr 13 put 0 0xF1 # Still a comment. Leading and trailing whitespaces are removed! #Also, noone cares there isn't a space after the hashtag. # Infinite loop :go_here jmp :go_here
Computational class
Rings was meant to participate in the aforementioned competition. As such, there are several restrictions imposed upon it. One of them is, that it must be possible to write a program for sorting lists of integers in under 100 bytes. For this reason, Rings is internally limited to 8 bit ring addresses, 8 bit ring lengths and 8 bit unsigned values. While these restrictions are in place to this day, much of the language's design has changed since, so it is currently unknown, if it's still possible to write a sorting program under 100 bytes of raw Rings bytecode.
If there weren't any of these restrictions and all of the aforementioned would be unbounded, Rings would be Turing complete. But since these restrictions are in place, Rings is actually a finite-state automaton.
Notable problems
- Rings has no error handling mechanism, so programmers must take care to handle all possible problems before executing instructions. One of the most common problems are illegal arithmetic operations, that would put an invalid value onto a ring.
Example programs
More example programs can be found on GitHub.
Cat
A simple cat program. Takes bytes until EOF (0xFF) and outputs them.
mkr 1 mkr 1 put 1 0xFF :loop inp 0 out 0 jlt 0 1 :loop
External resources
User:Ardemit, the author, has created an interpreter for Rings, that can be found on GitHub.