An intimate introduction to the Rainbow programming language

As a child, I had always been one to speculate things about the world around me, crafting beautifully absurd answers to questions I asked in my head. Such as, “How does that tree grow?” The natural answer, of course, is that small people live inside the tree and work all day to pull dirt from the roots and pack it into the end of the branches, growing them outwards. Of course I knew this was not a logical answer, but that knowledge didn’t keep me from imagining I lived in this beautiful reality.

Computers had always been a huge interest of mine as a child. Those mysterious beige boxes were machines of magic, able to take me on a journey to imagined worlds. No part of the experience of computing was overlooked or underimagined by me. Even the desktop was a strange realm that needed explored, and it’s inner workings imagined.

When my father introduced me to my first programming language over a decade ago, my world grew exponentially. He let me look behind the curtain, and had given me the knowledge to bring to life my imagination. With this new tool, Visual Basic, I was able to do anything. I wasted no time, and began creating.

Soon, I learned that the all powerful Visual Basic was not the only way one could program computers. There were, in fact, many other ways one could instruct these wonderful machines. This had my mind racing. I began imagining a vast expanse of programming languages. Much like the men in the tree, these programming languages were impractical and unrealistic creatures of my imagination. But, the more I learned about programming in the real world, the more beautiful these creatures became. They grew with me, and continue to grow, developing and changing just as I do.

Rainbow is one of those languages.

Rainbow is a language in which 6 character, 3 byte hex strings are encoded into pixel data of an image, providing instructions for the Rainbow VM.

Each hex string is referred to as a statement, and each statement is made up of 4 parts. The first part of a statement is the instruction to be executed on the Rainbow VM, and is defined by the first character of each statement. The second part of a statement is one of two 1 byte, 2 character parameters passed to the Rainbow VM with the instruction and is always a memory address. The third part of a statement is a single character switch indicating whether the last part of the statement is a value or memory address. This switch always has the value of either 1 or 0. The last two characters of a statement make up the second 1 byte parameter, a value or memory address depending on the state of the previous switch. If the executing instruction calls for a value as the second parameter, but a memory address is provided, the Rainbow VM will use the value of the cell at the address in execution.

For example: the statement 0xA05031 would execute the instruction at A with the address 0x05 and the value 0x31 as parameters. Additionally, the statement 0xA05131 would execute the instruction at A with the address 0x05 and the value of the cell at address 0x31 as parameters, due to the value/address switch being set to 1.

Here is a simple hello world program in Rainbow: Hello World!

This program is interpreted by the Rainbow VM as the following set of instructions (comments excluded):

0x100048  ;set cell 0x00 to value 0x48 (H)
0x101045  ;set cell 0x01 to value 0x45 (E)
0x10204C  ;set cell 0x02 to value 0x4C (L)
0x10304C  ;set cell 0x03 to value 0x4C (L)
0x10404F  ;set cell 0x04 to value 0x4F (O)
0x105020  ;set cell 0x05 to value 0x20 ( )
0x106057  ;set cell 0x06 to value 0x57 (W)
0x10704F  ;set cell 0x07 to value 0x4F (O)
0x108052  ;set cell 0x08 to value 0x52 (R)
0x10904C  ;set cell 0x09 to value 0x4C (L)
0x10A044  ;set cell 0x0A to value 0x44 (D)
0x10B021  ;set cell 0x0B to value 0x21 (!)
0x20010B  ;print values from cell 0x00 to cell 0x0B 
0x000000  ;exit with status code 0x00

 

The Rainbow VM currently has a set of 12 instructions, with capacity for a maximum of 16 instructions. These instructions are identified by the first character of each hex string passed to the VM, and are executed on an 256-cell tape with 8-bit memory cells.

For example: 0x10204C would result in the VM executing the command correlated with the character 1, the set instruction, which would set the memory cell at address 0x02 to the value of 0x4C.

The full list of Rainbow VM instructions, as well as more information about the Rainbow VM is available on the Rainbow project on GitHub.

The first Rainbow interpreter was written in C#.NET and was developed for a Computer Science House 24-hour hackathon. It implements all features of the Rainbow VM, and comes with some nice additions like output in hex, decimal, and ASCII. More information about the C# Rainbow interpreter is also available on GitHub.

Below are two more basic programs written in Rainbow:

factorial

This program takes an integer as input, calculates the factorial, and then prints the resulting value. As the Rainbow VM only has 1 byte memory cells, the maximum unsigned integer value that can be stored without undefined behavior is 255. This is problematic when doing math such as factorials. The greatest integer this program can calculate the factorial of without undefined behavior is 5.

fib

This program calculates the nth number in the Fibonacci Sequence, then prints the resulting value. As with the factorial calculator, this program is limited to memory cell size, and any number higher than the 13th number in the Fibonacci Sequence will produce undefined behavior.

Soon, I will be writing posts breaking down how exactly each of these programs work.