Рефал-05 — минималистичный самоприменимый компилятор минималистичного диалекта Рефала, имеющий общее подмножество с классическим Рефалом-5. На этом подмножестве он и написан.
Ставились две цели разработки:
- Компилятор должен быть минималистичным и самоприменимым. Т.е. с одной стороны, в нём должно быть достаточно выразительных возможностей для написания компилятора (самоприменение). С другой — он должен быть максимально легковесным (минимализм).
- Компилятор должен быть совместим с Рефалом-5, в частности, мог им раскручиваться. Это не значит, что он является точным подмножеством, это значит, что можно писать программы, которые одинаково работают на Рефале-5 и Рефале-05. И это общее подмножество достаточно выразимо для написания компилятора.
Удалось достичь объёма исходного кода примерно в 6000 строк, включая исходники компилятора, библиотеки встроенных функций, рантайма и скриптов сборки. И, по мнению автора, это минимум. Формально код можно уменьшить, сократив имена переменных и функций, но это пагубно сказалось бы на стиле исходного кода, ведь подразумеваемой целью были также понятные и прозрачные исходники.
Также целью было сделать не игрушку, вещь в себе, которая может только самоприменяться, но и сохранить возможности практического инструмента. Об этом в разделе «Установка и использование».
Разработка велась на основе старой версии Простого Рефала путём как отсечения избыточных возможностей, так и путём подгонки синтаксиса к Рефалу-5. Поэтому архитектурно и идейно он наследует Простой Рефал. Причём даже, по духу и идее он близок к Простому Рефалу версии 001, только при этом совместим с Рефалом-5 и в исходниках существенно меньше говнокода.
- Синтаксис напоминает базисное подмножество Рефала-5: фигурные скобки, имена переменных с точками, предложения только из образца и результата.
- Однако, есть важное отличие: все символы-слова должны быть именами функций в текущей области видимости.
- Функции можно вызывать косвенно:
<s.Func e.Arg>
. - Допустимы пустые функции без предложений — их вызов при любом аргументе приводит к ошибке отождествления. Пустые функции создаются только ради их имён.
- Синтаксический сахар для объявления пустых функций — ключевые слова
$ENUM
(локальная) и$EENUM
(entry):$EENUM FloatType, IntegerType, CharType, StringType;
- Псевдокомментарии — если комментарий начинается на
*$СЛОВО
иСЛОВО
является корректным ключевым словом, то текст комментария считается кодом на Рефале (в конце строки неявная;
). Предыдущую строку можно записать какТ.е. этот «комментарий» определит четыре пустые функции.*$EENUM FloatType, IntegerType, CharType, StringType
- В целях упрощения поддерживается только беззнаковая арифметика ограниченной разрядности (зависит от реализации) — как во встроенных арифметических функциях, так и в лексическом разборе. Это значит, что на очень длинные числа не будет выдано ошибки компиляции — оно будет проинтерпретировано как данное число по модулю размера машинного слова.
- Интерфейс с языком Си (чистый C89), вставки кода на Си в программах на Рефале. Это сделано для упрощения разработки библиотеки встроенных функций.
- Компиляция осуществляется в язык ANSI/ISO C89, это значит, что для сборки компиляции программ требуется компилятор языка Си.
- Размер символов-чисел равен размеру
unsigned long int
для используемого компилятора. - Поддерживается 28 встроенных функций Рефала-5:
- арифметика:
Add
,Compare
,Div
,Mod
,Mul
,Sub
— как уже сказано, беззнаковая и без контроля переполнения, - работа с типами символов:
Chr
,Explode
,Numb
,Ord
,Symb
,Type
— функцияExplode
возвращает имя для заданной функции, функцияNumb
не проверяет переполнение, - ввод-вывод:
Card
,Get
,Open
,Prout
,Putout
,Close
,ExistFile
, - операционная система:
Arg
,GetEnv
,Exit
,System
, - метафункция
Mu
— просто вызывает функцию по указателю, - копилка:
Br
,Dg
, - вспомогательная функция:
First
, - функция
ListOfBuiltin
, возвращающая список встроенных функций (она есть и в Рефале-5 тоже).
- арифметика:
Из соображений минимализма оставлены только те функции, которые реально
используются в компиляторе. Единственное исключение — функция Card
.
Потому что Рефал без поддержки перфокарт — это ущербный Рефал.
Для раскрутки компилятора у Вас должен быть установлен Рефал-5 версии
PZ Oct 29 2004
, набор библиотек для Рефала-5 refal-5-framework,
а также компилятор языка Си89.
Установите библиотеки репозитория Mazdaywik/refal-5-framework согласно инструкции в его README.
- Запустите файл
bootstrap.bat
. Cкрипт развёртки создаст файлc-plus-plus.conf.bat
и сообщит о том, что не указан компилятор языка Си. - Отредактируйте файл
c-plus-plus.conf.bat
(да, я его скопировал у Рефала-5λ и забыл переименовать), указав в нём командную строку для запуска компилятора (см. инструкции в самом файле). - Запустите ещё раз
bootstrap.bat
— компилятор должен успешно собраться и должны выполниться все автотесты (часть автотестов сообщают об ошибках синтаксиса, это так и должно быть).
Если у Вас установлен компилятор GCC (или Clang на macOS), то достаточно первого шага:
- Запустите файл
./bootstrap.sh
. В этом случае тоже будет создан файлc-plus-plus.conf.sh
, где по умолчанию будет указан компиляторgcc
, всё должно собраться (некоторые автотесты сообщат о синтаксических ошибках, это так и должно быть).
Если у Вас GCC не установлен, или для раскрутки желаете использовать другой
компилятор, то нужно будет отредактировать файл c-plus-plus.conf.sh
и запустить ./bootstrap.sh
повторно.
После раскрутки будет создана папка bin
, в которой будет располагаться
исполнимый файл refal05c.exe
(или refal05c
). Его уже можно запускать.
Если его вызвать с именем исходного файла, он скомпилирует его в исходник
на Си. Но, чтобы получать с его помощью получать исполнимые файлы, выполните
следующие действия:
- Добавьте в переменную
PATH
путь к папкеbin
данного дистрибутива. Тогда компилятор можно будет запускать из любой папки. - Установите переменную среды
R05CCOMP
с командной строкой запуска компилятора Си. Например,gcc -Wall -O3 -g
,cl /EHcs /W3 /wd4996 /O2
,bcc -w
. Когда эта переменная установлена,refal05c
будет вызывать сишный компилятор после генерации исходников. - Установите переменную среды
R05PATH
, указав в ней через точку с запятой (Windows) или двоеточие (unix-like) пути к папкамlib
иsrc
этого каталога. Например:илиset R05PATH=C:\Refal-05\lib;C:\Refal-05\src
В этом случае компилятор сможет находить и подключать библиотеки (рантайм и встроенные функции).export R05PATH="~/Refal-05/lib:~/Refal-05/src"
Примечание. На POSIX-системах (Linux или macOS) в переменную R05CCOMP
желательно добавлять -DR05_POSIX
(например, gcc -DR05_POSIX
) — в этом
случае функция System
будет корректно возвращать код возврата. Без данного
флага работать всё равно всё будет, только System
будет возвращать сырое
значение функции system
языка Си, которое может отличаться от фактического
кода возврата (см. man 2 wait
для более подробных сведений).
Классический пример — Hello, World!:
$ENTRY Go {
= <Prout 'Hello, World!'>
}
Сохраните этот текст в файл hello.ref
и выполните в командной строке команду
refal05c hello refal05rts Library
Здесь hello
— это имя нашего исходника (расширение .ref
здесь можно
не писать), refal05rts
— библиотека поддержки времени выполнения (на жаргоне —
«рантайм»), содержит функции, которые вызываются из сгенерированного кода,
и Library
— библиотека со встроенными функциями Рефала (той же Prout
).
В результате в текущей папке должен появиться файлик hello.c
— результат
компиляции в Си и исполнимый файл, который, в зависимости от операционной
системы и компилятора Си, может называться hello.exe
, a.exe
или a.out
.
Примечание. Некоторые компиляторы языка Си оставляют после себя мусор
из объектных файлов (.obj
) и других служебных файлов (.tds
, .pch
и т.д.), этот мусор можно (и нужно) удалять. Также можно удалить hello.c
.
Теперь мы можем запустить программу и увидеть что-то вроде:
Hello, World!
Как-то так.
За основу были взяты ранние коммиты Простого Рефала, но чутка переписаны.
- Все исходники были конвертированы в UTF-8, включая самый нижний коммит.
- Приписана правильная история к метке
003
. - Из истории удалены коммиты интерпретируемого представления, разработанного Игорем Дрогуновым. Я решил, что лучше очистить историю (сделав её более «прямой»), чем оставлять те правки, которые потом всё равно удалятся.
Исходную историю и исходные коммиты можно найти в репозитории Рефала-5λ.
Компилятор распространяется по двухпунктной лицензии BSD с оговоркой относительно компонентов стандартной библиотеки и рантайма — их можно распространять в бинарной форме без указания копирайта. При отсутствии данной оговорки для скомпилированных программ пришлось бы указывать копирайт самого компилятора, что неразумно.