Roco
- Дата создания:
- 13 октября 2007
- Парадигма:
- Типизация:
- Реализации и версии (свернуть все | развернуть все):
Roco — эзотерический язык программирования, основанный на понятии сопрограмм.
Roco был создан в 2007 году Lode Vandevenne, и его реализация остается фактическим стандартом и единственной существующей. Спецификация языка довольно проста, а сам язык не имеет коммерческой ценности, поэтому не проходил официальную стандартизацию.
Язык был создан для того, чтобы опробовать разные варианты работы с сопрограммами. На Roco можно реализовать Brainfuck, поэтому он является Тьюринг-полным.
Ключевым элементом языка являются сопрограммы — именованные части программы, которые не имеют ни входных или выходных параметров, ни локальных структур данных. По умолчанию каждая сопрограмма выполняется бесконечно, после окончания блока кода начинаясь заново. У каждой сопрограммы есть свой указатель инструкций, хранящий текущую команду сопрограммы. При вызове сопрограммы ее выполнение не начинается сначала, а продолжается с текущей команды; из-за этого рекурсию нельзя реализовать при помощи единственной сопрограммы, вызывающей себя же.
Единственная структура данных в программе — куча, в которой хранятся целые числа из 32 бит или больше. Обращаться к переменным можно по их индексам в куче, которые, в свою очередь, могут храниться в переменных.
Команды языка
В описании команд i
и o
обозначают входные и выходные параметры команды. Входные параметры могут быть как константами, так и переменными, выходные же — только переменными.
co X{}
: определить сопрограмму с именем X и телом, описанным в фигурных скобках.co X;
: объявить сопрограмму с именем X заранее. Реализация сопрограммы должна находиться позднее в той же области видимости программы.ro
: имя корневой сопрограммы.yi X
: вызвать сопрограмму X без изменения стека сопрограмм.ca X
: вызвать сопрограмму X с предварительным добавлением имени текущей сопрограммы в стек сопрограмм.ac
: действие, обратноеca
: извлекает верхний элемент стека сопрограмм и вызывает эту сопрограмму. Если стек пуст, завершает выполнение программы.if i
: еслиi
равно нулю, пропустить следующую команду.set o i
: записать значениеi
вo
.eq/neq/gt/lt o i1 i2
: записать вo
1, еслиi1
равно/не равно/больше/меньшеi2
, и 0 в противном случае.inc/dec o
: увеличить/уменьшить значениеo
на 1.add/sub/mul/div/mod/and/or/xor o i1 i2
: выполнить соответствующую операцию надi1
иi2
и поместить результат вo
(логические операции выполняются побитово).not o i
: инвертировать битыi
и поместить результат вo
.cout i
: напечатать символ по его ASCII-коду.cin o
: прочитать символ и записать его ASCII-код вo
.iout i
: напечатать число.iin o
: прочитать число и записать его вo
.
Элементы синтаксиса:
Комментарии, которые могут быть вложенными | /* ... */ |
---|---|
Регистрозависимость | да (только нижний регистр) |
Регулярное выражение идентификатора переменной | число (переменные не имеют имен) |
Регулярное выражение идентификатора функции | [_a-z][_a-z0-9]* |
Присваивание значения переменной | set varname value |
Тождественное равенство | eq o a b (записывает 0 или 1 в переменную o) |
Тождественное неравенство | neq o a b (записывает 0 или 1 в переменную o) |
Сравнение | gt lt |
Определение функции | co functionName {} |
Вызов функции | ca functionName |
Если - то | if i (если i=0, пропускает следующую инструкцию) |
Ссылки:
Примеры:
Hello, World!:
Пример для версий Roco 20071014В программе используется одна сопрограмма — главная. Она выводит сообщение посимвольно, используя ASCII-коды символов, и останавливается.
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
Числа Фибоначчи:
Пример для версий Roco 20071014Используется итеративное определение чисел Фибоначчи. Все числа хранятся в ячейках [2]..[17]. В ячейке [0] хранится номер следующего числа, ячейка [1] используется как временная переменная. Циклы реализованы как сопрограммы, поскольку по определению каждая сопрограмма выполняется циклически, до вызова другой сопрограммы или прерывания текущей.
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
Факториал:
Пример для версий Roco 20071014Используется итеративное определение факториала. В [0] хранится текущее число, [1] используется как временная переменная, в [2] хранится факториал текущего числа.
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:
Пример для версий Roco 20071014Пример подробно прокомментирован. Сопрограмма char
считывает символы в цикле и определяет, являются ли они буквами. Для обработки символов, окозавшихся буквами, вызывается другая сопрограмма, letter
, которая переводит их в нужный регистр и выводит. Отметим, что команда not
инвертирует все биты числа, поэтому ее нельзя использовать для инверсии логического значения (0 или 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
Комментарии
]]>blog comments powered by Disqus
]]>