Недавно с интересом узнал, что в своё время для компьютера Amiga много писали на модульных языках. Существовал даже
Amiga Modula & Oberon Klub (AMOK), который зарелизил
более сотни с лишним флоппи дисков с исходниками на Модуле и Обероне. Всё это доступно для скачивания. Некоторые исходники оттуда я скомпилировал практически без изменений в GPCP, Ofront и BlackBox Component Builder.
Ссылка, из которой я сам узнал об AMOKТранслятором Оберона для сборки этих исходников значится
Amiga-Oberon v3.11, F. Siebert / A+L AG. В исходниках присутствуют очень интересные расширения языка Oberon-2, о которых я может чуть позже расскажу подробнее. Сейчас пока по самым верхушкам:
При описании констант разрешено использовать функции из модуля SYSTEM:
Код: "OBERON"
CONST
idFTXT = SYSTEM.VAL (LONGINT, 'FTXT');
idCHRS = SYSTEM.VAL (LONGINT, 'CHRS');
Опции компилятора внутри комментариев (как в Turbo Pascal). Препроцессор с условными директивами:
Код: "OBERON"
(* $IFNOT GarbageCollector THEN $Implementation- $END *)
(* $SET Sorted $SET Sublists $SET SaveLoad $SET MultiUser (* $SET Check *) *)
(* $StackChk- $NilChk- $RangeChk- $OvflChk- $ClearVars- *)
Возможность явно разрешить компилятору не копировать при передаче параметров строковые массивы (необходимость этого расширения отпала в языке Компонентный Паскаль с появлением IN/OUT-параметров):
Код: "OBERON"
PROCEDURE Request(Text: ARRAY OF CHAR); (* $CopyArrays- *)
Явное освобождение указателей (на месте авторов я бы вынес это расширение в SYSTEM.DISPOSE):
Код: "OBERON"
DISPOSE (arg);
DISPOSE (currentdir)
А вот ALLOCATE наоборот вынесен в SYSTEM.ALLOCATE (не разобрался чем отличается от NEW; вероятнее всего, ALLOCATE и DISPOSE — это явное выделение и освобождение памяти, а NEW — только для работы со сборщиком мусора):
Код: "OBERON"
SYSTEM.ALLOCATE(gstore, GStoreSize);
Секция деинициализации модуля (также присутствует в языке КП):
Код: "OBERON"
BEGIN
NEW(RD);
CLOSE
IF RD # NIL THEN
d.FreeArgs (RD)
END;
END PCD.
Наряду с ключевым словом RECORD присутствует также слово STRUCT (не разобрался, чем отличается от RECORD):
Код: "OBERON"
SockAddrBase *= STRUCT
len *: (* UNSIGNED *) SHORTINT; (* total length *)
family *: (* UNSIGNED *) SHORTINT; (* address family *)
END;
Нетрассируемые указатели:
Код: "OBERON"
TYPE
DataPtr = UNTRACED POINTER TO ARRAY 18 OF LONGINT;
На закуску наиболее понравившееся мне расширение: типизированные константные массивы. По-моему, этого средства сильно не хватает Оберон-языкам, что заставляет эмулировать константные массивы через кодовые процедуры, читать из файлов, ресурсов и проч. Имею сильное желание подать эту идею авторам GPCP:
Код: "OBERON"
TYPE TheClocks = ARRAY 10 OF INTEGER;
CONST AnimClockData = TheClocks(
00400, 00070, 00000, 00700, 00100, 00380, 00000, 00700, 03008, 00000);