Introducing Edcoluj

I have just realized that I haven't yet mentioned here anything about my other language interpreter project: Edcoluj. Allow me to rectify that.

Edcoluj is the deliberately ugly name I have assigned to a small useless language I have been putting together. The original goal was not based on exposure to existing esoteric languages, which include INTERCAL and Whitepace, but rather in order to facilitate the composition of self modifying code. The result has ended up with properties reminiscent of Malbolge, Brainf***, and Redcode, although it is in no way designed to be particularly difficult to use, it simply makes nothing whatsoever easy1.

The program space in Edcoluj consists of an array of integers which is initially exactly as long as the number of tokens in the input source. This is no coincidence, as it is that same source which is stored in the array. There is also a separate program counter which is initially zero, and the interpreter runs the program by executing the instruction in the cell pointed to by the program counter and updating the program counter until an explicit stop instruction is reached, or the entire program space is deallocated. The cells in the program array are numbered starting at zero, and the array is wrapped around so that any possible address will always correspond to an existing cell. There are twelve instructions (or thirteen is one counts the no-op):

  1. Addition, adds the value at the address specified by the first following cell to the value at the address specified by the second following cell and stores the result to the address specified by the third following cell, and advances the program counter by 4.
  2. Subtraction, subtracts from the value at the address specified by the first following cell the value at the address specified by the second following cell and stores the result to the address specified by the third following cell, and advances the program counter by 4.
  3. Assignment, copies the value at the address specified by the first following cell to the address specified by the second following cell, and advances the program counter by 3.
  4. Jump, moves the program counter to the address specified by the first following cell.
  5. Equal Jump, If the value at the address specified by the first following cell is equal to the value at the address specified by the second following cell jumps to the address specified by the third following cell, otherwise advances the program counter by 4.
  6. Lesser Jump, If the value at the address specified by the first following cell is less than or equal to the value at the address specified by the second following cell jumps to the address specified by the third following cell, otherwise advances the program counter by 4.
  7. Greater Jump, If the value at the address specified by the first following cell is greater than or equal to the value at the address specified by the second following cell jumps to the address specified by the third following cell, otherwise advances the program counter by 4.
  8. Input, reads in a single character which is treated as an integer and stored to the address specified by the first following cell, and advances the program counter by 2.
  9. Output, writes out the value the address specified by the first following cell as a single character, and advances the program counter by 2.
  10. Stop, ends execution of the program.
  11. Allocate, increases the size of the program array by a number of cells equal to the value at the address given by the first following cell, filling the new cells with zeros, and advances the program counter by 2. May end the program by deallocating the entire program array.
  12. Deallocate, decreases the size of the program array by a number of cells equal to the value at the address given by the first following cell, and advances the program counter by 2. May end the program by deallocating the entire program array.

There is also the No Operation instruction, which has the value of 0. So that every address is also a valid instruction, any value outside the range [0,12] will be wrapped onto the range [1,12]. Note the this means that the no-op can only be represented as an explicit zero.

That's all there is to it; as mentioned above, it's not designed to be difficult, it just only supplies such basic operations that it makes doing anything useful rather tedious. Also, the source code is virtually illegible since it is impossible to differentiate among instructions, addresses, and data at a glance. Here's an example:

4 16 72 101 108 108 111 32 87 111 114 108 100 33 10 14 9 2 1 17 18 17 6 17 15 16 10

Those of you with your ASCII decoder rings close at hand will likely note the string "Hello World!n" embedded inside the code. This is the message to be printed. Stepping through the execution of this short program isn't hard. The first instruction, in cell 0 is an unconditional jump to address 16. At address 16 is an output instruction, which prints the value at address 2, namely the 'H'. After the output we arrive at cell 18 where we find an add instruction, which adds the values in cells 17 and 18 and stores the result back to cell 17. These two cells happen to be the address from which the output instruction prints and the add instruction itself. The effect, since the add instruction happens to be 12, is to increment the address from which the output instruction reads. Next comes the instruction at cell 22, a less-than jump. If the value in cell 17, again that output address, is smaller than the value in cell 15, which is 14, then execution will jump back to cell 16. This is a loop, which will keep going until the output address reaches 15, one cell beyond the end of the string to be printed. WHen this happen the conditional jump will not occur, and control will reach cell 26, which instructs the program to end.

Since the language itself is quite simple, writing the interpreter isn't actually all that much work; I'm on it's third revision. The first was in Objective-C for some reason, and the second in C as an attempt at a Windows port, that I could never get to work without getting a peculiar error when the program exited. The current version is by far the best, it is now in C++ and has some extra features, namely a minimal version of the language which has only the no-op, subtraction, less-than jump, input, output, and allocate instructions, and an interactive debugger which supports breakpoints and watchpoints. I'm pretty happy with how this language has come out, in that while it's not near as tough as Malbolge, it is both simple enough to make working with it possible for fun and annoying enough to make doing so a challenge.


  1. I find the similarities of my creation to Redcode rather interesting since when I wrote down the core specifications I had never heard of Redcode. I think that they may have come about due to a certain similarity of purpose; the goal of Core War is to provide a battle ground for programs to mess each other up, while my goal was to provide a slate upon which a program may mess itself up. 

  2. This is a marvelous little space saving obfuscation; the need to use space for simple constants like 1 can be eliminated by using nearby instructions as the constants. 

No Comments

Comment on this post