Roco
- Appeared in:
- 13 Oct 2007
- Paradigm:
- Typing discipline:
- Versions and implementations (Collapse all | Expand all):
Roco is an esoteric programming language based on the concept of coroutines.
Roco was created in 2007 by Lode Vandevenne, and his implementation remains a de facto standard (not to mention that it’s the only one available). Its specification is rather simple, and the language itself has no commercial value, so it hasn’t been standardized.
Roco was created to try out some variations of handling coroutines. It is Turing-complete, as Brainfuck can be implemented in it, and thus theoretically capable of executing any real-life task.
Coroutines are the main element of the language; they are named parts of the program which have neither input or output parameters, nor local variables. Each coroutine has its own instruction pointer which stores the current command. By default coroutines loop forever: once the instruction pointer has reached the end of the coroutine, it moves again to its start. When a coroutine is called, its execution starts not from the start, but from the last position of its instruction pointer; this means, for example, that the recursion can’t be implemented using a single coroutine calling itself.
The only data structure in the language is a heap which stores 32-bit integer variables. The variables can be referenced by their index within the heap, which in turn can be stored in a variable (this variable being a pointer).
Language Instructions
Here i
and o
denote input and output parameters. Input parameters can be either variables or constants, while output parameters can be only variables.
co X{}
: define a coroutine named X; coroutine body is in brackets.co X;
: declare a coroutine named X; implementation must follow later within the same scope.ro
: the name of the root coroutine (doesn’t have to be defined explicitly).yi X
: yield to coroutine X, don’t change the coroutines stack.ca X
: call coroutine X: push its address to the coroutines stack and yield to X.ac
: inverse ofca
: pop address from the coroutines stack and yield to this coroutine. If the stack is empty, program execution stops.if i
: ifi
is zero, skip next command.set o i
: store value ofi
in variableo
.eq/neq/gt/lt o i1 i2
: put 1 in variableo
, ifi1
equals/not equals/is greater/is less thani2
, and put 0 otherwise.inc/dec o
: increment/decrement the value ino
.add/sub/mul/div/mod/and/or/xor o i1 i2
: execute corresponding operation oni1
andi2
and put the result too
(logic operations are done bitwise).not o i
: invert bits ofi
and put the result too
.cout i
: print a character by its ASCII-code.cin o
: read a character and put its ASCII-code too
.iout i
: print a number.iin o
: read a number and put it too
.
Elements of syntax:
Nestable comments | /* */ |
---|---|
Case-sensitivity | yes (only lowercase allowed) |
Variable identifier regexp | [number] (no variable names) |
Function identifier regexp | [_a-z][_a-z0-9]* |
Variable assignment | set varname value |
Deep equality | eq o a b (put 0 or 1 to variable o) |
Deep inequality | neq o a b (put 0 or 1 to variable o) |
Comparison | gt lt |
Function definition | co functionName {} |
Function call | ca functionName |
If - then | if i (skip next instruction if i=0) |
Links:
Examples:
Hello, World!:
Example for versions Roco 20071014This code uses only main coroutine; it outputs the message character by character, using their ASCII codes, and stops.
cout 72
cout 101
cout 108
cout 108
cout 111
cout 44
cout 32
cout 87
cout 111
cout 114
cout 108
cout 100
cout 33
ac
Fibonacci numbers:
Example for versions Roco 20071014This example uses iterative definition of Fibonacci numbers by saving them all in cells [2]..[17]. Cell [0] stores the index of the next number to be calculated, and cell [1] is used as temporary storage. Loops are implemented as coroutines, since by definition coroutines loop until another coroutine is called or execution is interrupted with ac command.
co calc{
/* break the loop when the counter is 2+16, since numbers start with cell 2 */
eq [1] [0] 18
if [1] ac
/* calculate next number and store it to [[0]]*/
sub [1] [0] 1
set [[0]] [[1]]
sub [1] [0] 2
add [[0]] [[0]] [[1]]
/* output */
iout [[0]]
cout 44
cout 32
/* increment counter */
add [0] [0] 1
}
/* initialize with first Fibonacci numbers */
set [0] 4
set [2] 1
set [3] 1
iout [2]
cout 44
cout 32
iout [3]
cout 44
cout 32
ca calc
cout 46
cout 46
cout 46
ac
Factorial:
Example for versions Roco 20071014This example uses iterative definition of factorial. Cell [0] stores the current number, cell [1] is temporary, and cell [2] stores factorial of current number.
co calc{
/* break the loop when the counter is 17 - the number for which we don't need factorial */
eq [1] [0] 17
if [1] ac
/* output current factorial */
iout [0]
cout 33
cout 32
cout 61
cout 32
iout [2]
cout 13
cout 10
/* calculate next number and store it to [2]*/
add [0] [0] 1
mul [2] [2] [0]
}
/* initialize with 0! = 1 */
set [0] 0
set [2] 1
ca calc
ac
CamelCase:
Example for versions Roco 20071014The example is commented in detail. Coroutine char
reads characters from standard input one by one and checks whether they are letters. Coroutine letter
is called for characters which turned out to be letters; it converts them into required case and prints them. Note that not
command inverts all bits of the number, so it can’t be used to negate a logical value (which is stored as 0 or 1) — one has to subtract this value from 1.
/* [0] - current character
[1] - last character was space?
rest are temporary variables (used within one iteration only)
*/
co letter{
/* coroutine to process the case of a known letter */
/* if it is uppercase, and last one was letter, change to lowercase */
sub [4] 1 [1]
and [5] [2] [4]
if [5]
add [0] [0] 32
/* if it is lowercase, and last one was space, change to uppercase */
and [5] [3] [1]
if [5]
sub [0] [0] 32
/* print the character */
cout [0]
set [1] 0
ac
}
co char{
/* read next character to [0] */
cin [0]
/* break the loop when the next character is end-of-line (ASCII 10) */
eq [2] [0] 10
if [2] ac
/* check whether this character is a letter at all [2] - uppercase, [3] - lowercase, [4] - at all, [5]-[6] - temporary */
/* uppercase */
gt [5] [0] 64
lt [6] [0] 91
and [2] [5] [6]
/* lowercase */
gt [5] [0] 96
lt [6] [0] 123
and [3] [5] [6]
/* at all */
or [4] [2] [3]
sub [5] 1 [4]
/* if this is not a letter, ONLY change [1] */
if [5]
set [1] 1
/* otherwise, call the coroutine to handle this */
if [4]
ca letter
}
/* at the start mark that last character was space */
set [1] 1
ca char
ac
Comments
]]>blog comments powered by Disqus
]]>