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 256 unsigned 8 bit integers (but cannot be zero-length) and can rotate counter-clockwise up to 256 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 an 8-bit unsigned integer (B), a ring index (R) or a label (L)
Instruction | Arguments | Description |
---|---|---|
mkr | B | Creates a new ring. The argument specifies the length. |
put | R B | The first argument specifies a ring, the second a literal value, that will be put onto said ring. |
rot | R B | The first argument specifies a ring, the second a literal value, that will tell the ring how many steps to rotate. |
swp | R R | Both arguments represent rings. The values on these rings will be swapped. |
inp | R | Reads a value from stdin and puts it onto the ring specified by the argument. |
out | R | Writes the value on the ring specified by the argument to stdout. |
err | R | Writes the value on the ring specified by the argument to stderr. |
add | R R R | All arguments represent rings. Add the values on the first two rings and put them onto the third. (A+B=C) |
sub | R R R | 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 | R R R | All arguments represent rings. Multiply the values of the first two rings and put the result onto the third. (A*B=C) |
div | R R R | 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 | L | The argument is a label, that the interpreter unconditionally jumps to. |
jeq | R R 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 | R R 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 | R R 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 | B | Halts the program, with the argument representing an exit code literal. |
Syntax
There are two kinds of statements, instructions and labels. Statements and instruction arguments must be separated by at least a single whitespace character, but otherwise there are no restrictions.
Labels act as instruction pointers in jump instructions and are defined using the :
(colon) character, followed by a unique name. 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. Instruction names are case-insensitive.
System | Prefix | Example | Decimal value |
---|---|---|---|
Decimal | 182 | 182 | |
Hexadecimal | 0x | 0xB6 | 182 |
Hexadecimal | 0X | 0XB6 | 182 |
Octal | 0 | 0266 | 182 |
Binary | 0b | 0b10110110 | 182 |
Anything past a #
character is considered a comment and is ignored.
The following is a valid Rings program using all the rules described in this section:
mkr 13 pUT 0 0xF1 # Declare a ring with a total length of 13 and put 241 on it
# 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 were to 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 built-in error handling mechanism, so programmers must take care to handle all possible problems before executing instructions.
- Rings only works with 8-bit unsigned integers and has no bit-shifting instructions, making signed operations very hard to implement.
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 # Ring 0 – IO cell mkr 1 put 1 0xFF # Ring 1 – Constant cell 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.