Rings

From Esolang
Jump to navigation Jump to search
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 much closer to being a linear bounded automaton.

Notable problems

  • Rings doesn't have a straightforward way of handling EOF, because it only works with unsigned 8-bit integers and thus cannot distinguish what is a valid input and when EOF has been reached. In most cases, 0xFF should be considered EOF.
  • 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.