]]> ]]>
Править | Обсудить | История

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

]]>

Работа программистам