Сообщение о языке Oberon-Deft
Язык является модификацией языка Oberon-7
Ревизия: v0.0.1 / 2023-07-27
Все должно быть сделано максимально просто, но не примитивно. (А. Эйнштейн)
0. Введение 1. Синтаксис 2. Словарь 3. Ключевые символы
Идея создания языка Oberon-Deft (Оберон умелый) родилась после переосмысления идей несоответствия современного ИТ и средств разработки. Никлаус Вирт продвинулся в этом отношении дальше всех. И львиная доля идей в концепции Oberon-Deft является либо прямой трансляцией этих идей, либо непосредственно развивают их.
Oberon-Deft — язык программирования общего назначения, который является развитием Модулы-2 и модификацией Оберон-7.
Данная вариация по большей части не имеет принципиально новых концепций, новые части отдельно описаны в соответствующих разделах. Концепция позволяет максимально изолировать высокоуровневые средства от низкоуровневых.
Назначение этого документа в том, чтобы служить эталоном для программистов, разработчиков и авторов руководств. Если о чём-то не сказано, то обычно это ошибка. Этот документ описывает язык как достаточный для реализации различного рода ПО: начиная от загрузчиков ОС, сами ОС системное и прикладное ПО.
Законченный текст на языке программирования Oberon-Deft называется программа.
Программа включает как минимум один модуль. В программе как правило модулей как правило больше одного, количество модулей в программе не ограничено. Каждый модуль должен обладать правильной структурой:
МОДУЛЬ Старт;
КОНЕЦ Старт.
Модуль может содержать бесконечное множество правильно сформированных предложений, в соответствии с синтаксисом языка. Набор предложений Oberon-Deft ограничивается модулем. Каждое предложение представляет собой конечную последовательность символов из конечного словаря. Словарь Oberon-Deft состоит из сущностей:
Все эти сущности входят в группу дерево символов и состоят из литер. (Обратите внимание на разницу между символами и литерами). Дерево символов кроме самих сущностей содержит связи сущностей и все их необходимые атрибуты. Листья дерева не могут видеть другие листья, находящиеся ниже по веткам или в соседних ветках. Также есть ряд отдельных случаев описанных ниже.
Для описания синтаксиса используются вариант расширенной формы Бэкуса — Наура (РБНФ). Квадратные скобки [ и ] означают необязательность записанного внутри них выражения, а фигурные скобки { и } означают его повторение (возможно 0 раз).
Синтаксические сущности (символы) обозначаются русскими словами (английскими эквивалентами), выражающими их функциональное назначение. Символы могут быть на любом языке, ограничений нет. Символы словаря языка программирования обозначаются литеральными строками, заключенными в кавычки или литерами.
В группу литеры входят несколько классов:
буква;цифра;оператор;разделитель.Разделитель включает в себя:
пробел;перенос строки.Для составления символов предусматривается использование следующих правил. Пробелы и переносы строк не должны встречаться внутри символов (исключая комментарии). Они игнорируются, если они не существенны для отделения двух последовательных символов. Заглавные и строчные буквы считаются различными.
Имена — последовательности букв и цифр. Первая литера должна быть буквой.
имя = буква {буква | цифра}.
Примеры:
x Сканер Оберон Символ_Получить перваяЛитера name2
В группу числа входят символы:
целые числа;дробные числа.Целые числа являются последовательностью цифр и могут быть продолжены литерой суффикса слитно за числом. Если суффикса нет, то представление десятичное. Суффикс H обозначает шестнадцатеричное представление.
Дробное число всегда содержит десятичную точку. Допускается чтобы оно было представлено целым десятичным числом. Литера E означает «умножить на десять в степени».
цифра = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".
шестнЦифра = цифра | "A" | "B" | "C" | "D" | "E" | "F".
целое = {знак} цифра {цифра} | цифра {шестнЦифра} "H".
дробное = {знак} цифра {цифра} "." {цифра} [Порядок].
Порядок = ("E") ["+" | "-"] цифра {цифра}.
число = целое | дробное.
Примеры:
1987 100H = 256 12.3 4.567E8 = 456700000
Строковые литералы — последовательность литер, заключенных в двойные кавычки ". Ограничивающая кавычка не должна встречаться внутри литерала, но допускается:
Число литер в литерале называется длиной строкового литерала.
строка = " {литера} " | цифра {шестнЦифра} "X".
Примеры:
"ОБЕРОН" "Don't worry!" 22X "Hey, \"world\"!"
Все имена символов делятся на две группы:
ключевые символы (предопределены заранее);пользовательские символы (определяются пользователем).В группу ключевых символов входят:
предписания (сложные сущности, управляющие потоком программы);операторы (простые сущности ,управляющие действиями);разделители (простые сущности, разделяющие другие сущности).Ключевые символы являются специальной группой и они не могут использоваться в качестве пользовательских символов ни в какой части программы.
Ниже перечислен полный список ключевых имволов
| Символ | Комментарий |
|---|---|
| + | Сложение |
| ++ | Инкремент операнда |
| += | Сложение операндов с присвоением операнду слева |
| = | Присвоение |
| - | Минус |
| -- | Декремент |
| -= | Вычитание операндов, с присвоением операнду слева |
| ^ | Исключающее ИЛИ |
| ^= | Исключающее ИЛИ с присвоением операнды слева |
| * | Умножение |
| ** | Возведение в степень |
| **= | Возведение в степень с присвоением операнда слева |
| / | Деление |
| /= | Деление с присвоением операнду слева |
| ~ | Отрицание |
| < | Меньше |
| > | Больше |
| & | Логическое И |
| &= | Логическое И с присвоением операнду слева |
| = | Присвоить |
| // | Линейный комментарий |
| /* | Начало многострочного комментария |
| */ | Конец многострочного комментария |
| (* | Начало многострочного комментария |
| *) | Конец многострочного комментария |
| . | Точка |
| <= | Меньше или равно |
| , | Запятая |
| >= | Больше или равно |
| ; | Точка с запятой |
| ... | Перечисление |
| | | Логическое ИЛИ |
| : | Определить тип переменной |
| ( | Открывающая круглая скобка (выражение) |
| ) | Закрывающая круглая скобка (выражение) |
| [ | Открывающая квадратная скобка (массив) |
| ] | Закрывающая квадратная скобка (массив) |
| { | Фигурная открывающая скобка (область видимости) |
| } | Закрывающая фигурная скобка (область видимости) |
| ВНУТРИ | IN Определение вхождения |
| ДО | TO До указанного значения далее |
| ПО | BY Шаг приращения (цикл) |
| ЕСТЬ | IS Проверка типа |
| ДА | TRUE Булево значение |
НЕТ FALSE Отрицание логического значения ПРОВЕР SWITCH Проверка на выбор ВЫБОР CASE Вариант выбора ТИП TYPE Объявление типа МАССИВ ARRAY Массив элементов ИМПОРТ IMPORT Импорт модуля ЕСЛИ IF Начало условия ТОГДА THEN Действие после условия МОД MOD Модуль от целочисленного деления МОДУЛЬ MODULE Объявление начала модуля КОНСТ CONST Объявление константы ПОКА UNTIL Условие продолжения цикла на выходе ДИВ DIV Остаток от целочисленного деления НИЧ NIL Пустое состояние объекта ЗНАЧ VAR Объявление переменной ПОКА WHILE Условие проверки продолжения цикла на входе ИЗ OF Указание типа массива ИЛИ OR Логическое ИЛИ @
Ссылка на объект ИНАЧЕ
Альтернативная ветка ЕСЛИ ФН FN Объявление функции СТРУКТ STRUCT Объявление структуры ПОВТОР REPEAT Повторить выполнение ДЛЯ FOR Объявление цикла ВЕРНУТЬ RETURN Возврат из функции МУТ MUT Признак изменяемости
Группа символов комментарии могут быть вставлены между любыми двумя символами в программе. Они являются произвольными последовательностями литер, которые открываются /, ( и закрываются с помощью */, *). Однострочные комментарии начинаются на // и действуют до конца строки. Комментарии не влияют на смысл программы. Они могут быть вложенными.
Следующие имена являются стандартными (группа ключевых слов); их значение определено в разделе 6.1 (типы) и 10.2 (процедуры):
ABS ASR ASSERT BOOLEAN BYTE
CHAR CHR DEC EXCL FLOOR
FLT INC INCL INTEGER LEN
LSL NEW ODD ORD PACK
REAL ROR SET UNPK
Константное выражение может быть вычислено по его тексту без фактического выполнения программы. Его операнды — константы (см. Гл. 8). Примеры объявлений констант:
число = 100
лимит = 2*N - 1
словаВсе = {0 .. словаРазмер -1}
имя = "Oberon"
ОбъявлениеТипа = ИмяОпр "=" Тип.
Тип = ИмяКвал | ТипМассив | ТипЗапись | ТипСсылка | ПроцедурныйТип.
Примеры:
мТаблица = ARRAY 255 OF REAL
туДерево = POINTER TO тУзел
тУзел = RECORD
ключ: INTEGER;
уЛевый, уПравый: туДерево
END
туДеревоСередина = POINTER TO тУзелСередина тУзелСередина = RECORD (тУзел)
мИмя: ARRAY 32 OF CHAR;
уПодузел: туДерево
END
тпФункция = PROCEDURE (x: INTEGER): INTEGER
6.1 Встроенные типы Следующие встроенные типы обозначаются заранее объявленными именами. Связанные операторы определены в 8.2, а встроенные функции - в 10.2. Значения заданного встроенного типа следующие:
BOOLEAN -- принимает значения TRUE и FALSE
CHAR -- литеры стандартного набора, размер зависит от реализации
INTEGER -- целые числа, размер зависит от реализации
REAL -- дробные числа, размер зависит от реализации
BYTE -- целые числа от 0 до 255, размер фиксированный в 8 бит
SET -- набор целых чисел между 0 и пределом, зависящим от реализации
Тип BYTE совместим с типом INTEGER, и наоборот.
6.2 Тип массив Массив - это структура, состоящая из фиксированного количества элементов, тип элементов одинаковый для всех элементов данного типа массива. Количество элементов массива называется его длиной. Элементы массива обозначаются индексами, которые являются целыми числами от 0 до (длины - 1).
ТипМассива = ARRAY длина {"," длина} OF тип_элемента.
длина = КонстантноеВыражение.
Форма объявления
ARRAY N0, N1, ..., Nk OF T
понимается как сокращение для объявления
ARRAY N0 OF
ARRAY N1 OF
...
ARRAY Nk OF T
Примеры типов массивов:
ARRAY NN OF INTEGER
ARRAY 10, 20 OF REAL
6.3 Тип запись Тип записи - это структура, состоящая из фиксированного количества элементов возможно разных типов. Объявление типа записи задаёт для каждого элемента, которое называется полем, его тип и имя, которое обозначает (ссылается на) это поле. Область действия этих имён полей - само определение записи, но они также видны как части экземпляра записи в форме "через точку" (см. 8.1), которая ссылается на элементы самого экземпляра записи.
ТипЗаписи = RECORD ["(" БазовыйТип")"] [СписокПолейТипа] END.
БазовыйТип = квалификатор.
СписокПолейТипа= СписокПолей{";" СписокПолей}.
СписокПолей = СписокИмён":" тип.
СписокИмён= ИмяОбъявление{"," ИмяОбъявление}.
Если тип записи экспортируется, имена полей, которые должны быть видимыми вне модуля объявления, должны быть помечены. Они называются публичными полями; неотмеченные поля называются приватными полями. Типы записей являются расширяемыми, т. е. тип записи может быть определён как расширение другого типа записи. В приведенных выше примерах УзелСередина (непосредственно) расширяет Узел, который является (прямым) базовым типом УзелСередина. Точнее, УзелСередина расширяет Узел с полями имя и подузел. Определение. Тип T расширяет тип T0, если он является T0, или если он непосредственно расширяет расширение T0. И наоборот, тип T0 является базовым типом для типа T, если он является T, или если он является прямым базовым типом базового типа T. Примеры типов записей:
RECORD день, месяц, год: INTEGER
END
RECORD
имя, фамилия: ARRAY 32 OF CHAR;
возраст: INTEGER;
зарплата: REAL
END
6.4 Тип ссылка Переменные ссылки типа P принимают в качестве значений ссылки на переменные некоторого типа T. Этот тип должен быть типом записи. Ссылка типа P называется связанным с T, а T - базовым типом для ссылки P. Типы ссылок наследуют отношение расширения их базовых типов (если они есть). Если тип T является расширением T0 и P является типом ссылки, связанным с T, то P также является расширением P0, тип ссылки, связанный с T0.
ТипСсылка = POINTER TO тип .
Если тип P определён как POINTER TO T, тип T может быть текстуально объявлен после объявления P, но [если это так] он должен находиться в пределах одной области. Если p - переменная типа P = POINTER TO T, то вызов предопределённой процедуры NEW (p) имеет следующий эффект (см. 10.2): переменная типа T выделяется в свободном хранилище памяти, а ссылка на неё присваивается p. Эта ссылка p имеет тип P, а ссылочная переменная p^ имеет тип T. Отказ распределения памяти под структуру приводит к тому, что p получает значение NIL. Каждой переменной-ссылку может быть присвоено значение NIL, которое вообще не указывает на какую-либо переменную. 6.5 Процедурный тип Переменные процедурного типа T принимают процедуру (или NIL) в качестве значения. Если процедуре P присвоена переменная процедурного типа T, формальные параметры (типа) P должны быть такими же, как те, что указаны в формальных параметрах T. То же самое справедливо для типа результата в случае (См. 10.1). P не должен быть объявлен локальным для другой процедуры, и не может быть стандартной процедурой.
ПроцедурныйТип = PROCEDURE [ФормальныеПараметры].
ОбъявлениеПеременной = СписокИмён":" тип.
Переменные, имена которых отображаются через запятую имеют один и тот же тип. Примеры объявления переменных (см. Примеры в главе 6):
i, j, k: INTEGER
x, y: REAL
p, q: BOOLEAN
s: SET
f: Function
a: ARRAY 100 OF REAL
w: ARRAY 16 OF
RECORD
лит: CHAR;
счётчик: INTEGER
END
t: Дерево
8.1 Операнды За исключением наборов и литерных констант, то есть чисел и строк, операнды обозначаются именами. Обозначение операнда состоит из имени, относящегося к константе, переменной или процедуре, которая будет обозначена. Такое имя может быть определено как имя модуля (см. Главы 4 и 11), и за ним могут следовать селекторы, если назначенный объект является элементом структуры. Если A обозначает массив, то A[E] обозначает тот элемент массива A, индекс которого является текущим значением выражения E. Тип E должен иметь тип INTEGER. Обозначение вида A[E1, E2, ..., En] обозначает A[E1][E2]...[En]. Если p обозначает переменную-ссылку, p^ обозначает переменную, на которую ссылается p. Если r обозначает запись, то r.f обозначает поле f из записи r. Если p обозначает ссылку, p.f обозначает поле f записи p^, то есть точка подразумевает разыменование, а p.f означает p^.f. Охрана типа v(Т0) проверяет, что v имеет тип T0, то есть охрана типа прекращает выполнение программы, если v не типа T0. Охрана применима, если
v - параметр, как переменная типа записи, или v - ссылка.
ссылка = Квалификатор {селектор} селектор = "." Имя | "["СписокВыражения"]" | «^» | "(" Квалификатор ")" СписокВыражения = выражение {"," выражение}.
Если обозначенный объект является переменной, то имя переменной ссылается на текущее значение переменной. Если объект является процедурой, то имя процедуры без списка параметров ссылается на эту процедуру. Если за ним следует список параметров (возможно, пустой), имя подразумевает активацию процедуры и обозначает значение, полученное в результате её выполнения. Фактические параметры (используемых типов) должны соответствовать формальным параметрам, указанным в объявлении процедуры (см. Главу 10). Примеры обозначений (см. Примеры в главе 7):
i (INTEGER)
а[I] (REAL)
w[3].ch (CHAR)
t.ключ (INTEGER)
t.левый.правый (Дерево)
t(УзелСредний).подузел(Дерево)
8.2 Операции Синтаксис выражений различает четыре вида операций с разными приоритетами (порядком выполнения). Операция ~ имеет наивысший приоритет, за которым следуют операции умножения, сложения и отношения. Операции одного и того же приоритета выполняются слева направо. Например, x-y-z означает (x-y)-z.
выражение = ПростоеВыражение [отношение ПростоеВыражение].
отношение = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS.
ПростоеВыражение = ["+"|"−"] разделитель {ОператорАддикции разделитель}.
ОперациярАддикции= "+" | "−" | OR.
разделитель = множитель {ОператорМультипликации множитель}.
ОператорМультипликации = "*" | "/" | DIV | MOD | "&" .
множитель = число| строка| NIL | TRUE | FALSE | set | ссылка [ФактическийПараметр] | "(" выражение ")" | "~" множитель.
set = "{" [элемент {"," элемент}] "}".
элемент = выражение [".." выражение].
ФактическийПараметр = "(" [СписокВыражения] ")" .
Множество {m..n} обозначает {m, m + 1, ..., n-1, n}, а если m>n, то пустое множество. Доступные операции перечислены в следующих таблицах. В некоторых случаях несколько разных операций обозначаются одним и тем же символом операции. В этих случаях фактическая операция определяется типом операндов. 8.2.1 Логические операции
Символ Результат
OR логическая дизъюнкция
& логическое соединение
~ логическое отрицание
Эти операции применяются к операндам BOOLEAN и дают результат BOOLEAN.
р OR q означает «если р, то TRUE, иначе q»
p & q обозначает «если р, то q, иначе FALSE»
~ P означает "не p"
8.2.2 Арифметические операции
Символ Результат
+ сумма
- разница
* умножение
/ деление
DIV целое частное
MOD модуль
Операции +, -, * и / применяются к операндам числовых типов. Оба операнда должны быть одного типа, что также определяет тип результата. При использовании в качестве унарных операций "-" обозначает инверсию знака, а "+" обозначает операцию идентичности. Операции DIV и MOD применяются только к целочисленным операндам. Пусть q = x DIV y, а r = x MOD y. Тогда множитель q и остаток r определяются уравнением
X = q * y + r 0 <= r < y
8.2.3 Операторы наборов
Символ Результат
+ объединение
- разность
* пересечение
/ cимметричная разность наборов
.
Когда используется с одним операндом типа SET, знак минус обозначает дополнение набора. 8.2.4 Отношения
Символ Результат
= равно
# неравно
< меньше
<= меньше или равно
> больше
= больше или равно
IN членство в наборе
IS проверка типа
Результат операций отношения является базовым типом BOOLEAN. Отношение упорядочения <, <=,>,> = применяется к числовым типам, CHAR и литерным массивам. Отношения = и # применимы также к типам BOOLEAN, SET, ссылкам и процедурным типам. x IN s означает "x является элементом s". x должен иметь тип INTEGER и s должен быть типом SET. v IS T означает «v имеет тип T» и вызывает проверку типа. Это применимо, если
1. T - расширение объявленного типа T0 для v, и если
2. v - параметр, как переменная типа записи или v - ссылка.
Предполагая, например, что T является расширением T0 и что v является ссылкой на тип T0, тогда проверка v IS T определяет, является ли фактически указанная переменная (также, а не только T0) типом T. Значение NIL IS T не определено. Примеры выражений (см. Примеры в главе 7):
1987 (INTEGER)
I DIV 3 (INTEGER)
~ P OR q (BOOLEAN)
(I + j) * (i-j) (INTEGER)
S - {8, 9, 13} (SET)
A [i + j] * a [i-j] (REAL)
(0 <= i) & (i <100) (BOOLEAN)
T.ключ = 0 (BOOLEAN)
K IN {i .. j-1} (BOOLEAN)
T IS УзелСредний (BOOLEAN)
Предписания Предписания обозначают действия. Есть простые и сложные предписания. Простые предписания не состоят из каких-либо частей, которые сами являлись бы предписаниями. Простые предписания -- просто присваивания, либо вызов процедур. Сложные предписания состоят из частей, которые сами являются предписаниями. Они используются, чтобы выразить последовательное и условное, выборочное и повторное действие. Предписания также могут быть пустыми, и в этом случае они не обозначают никаких действий. Пустое предписание включено в язык для того, чтобы ослабить правила пунктуации в последовательностях предписаний.
Предписание = [Присвоение | ВызовПроцедур | Предписание_IF | Предписание_CASE | Предписание_WHILE | Предписание_REPEAT | Предписание_FOR].
9.1 Предписание ПРИСВОЕНИЕ Элементарное предписание ПРИСВОЕНИЕ служит для замены текущего значения переменной на новое значение, заданное выражением. Предписание ПРИСВОЕНИЕ записывается как «:=» и произносится как «присвоить».
присвоение = переменная ":=" выражение.
Если значение параметра обладает структурой (массив или тип записи), параметру не разрешено присваивать его или его элементам. Импортируемые переменные также не могут быть присвоены. Тип выражения должен быть таким же, как у переменной. Имеют место следующие исключения:
1. Константу NIL можно присвоить переменным любого типа ссылки или процедуры.
2. Строки могут быть назначены любому массиву литер, если количество литер в строке меньше, чем количество литер в массиве. (Добавляется литера с кодом ноль). Однолитерные строки также могут быть присвоены переменным типа CHAR.
3. В случае записей тип источника должен быть расширением типа адресата.
4. Открытый массив может быть назначен массиву равного базового типа.
Примеры присвоений (см. Примеры в главе 7):
i := 0
p := i = j
x := FLT(i + 1)
k := (i + j) DIV 2
f := log2
s := {2, 3, 5, 7, 11, 13}
a[i] := (x+y) * (x-y)
t.key := i
w[i+1].ch := "A"
9.2 Предписание ВЫЗОВ_ПРОЦЕДУРЫ Простое предписание ВЫЗОВ_ПРОЦЕДУРЫ служит для активации процедуры. Вызов процедуры может содержать список фактических параметров (аргументов), которые заменяются вместо соответствующих формальных параметров (параметров), заданных в объявлении процедуры (см. Главу 10). Соответствие устанавливается порядком параметров в списках аргументов и параметров соответственно. Существуют два вида параметров: переменные и значения. В случае параметров, как переменных -- аргумент должен быть ссылкой, обозначающим переменную. Если он указывает на элемент структурной переменной, селектор вычисляется, когда устанавливается аргумент, то есть перед выполнением процедуры. Если параметр является значением, соответствующий аргумент должен быть выражением. Это выражение вычисляется до активации процедуры, и результирующее значение присваивается аргументу, который теперь представляет собой локальную переменную (см. Также 10.1.).
Вызов_Процедуры = Переменная [Актуальные_Параметры].
Примеры вызова процедур:
Целое_Читать(i) (см. Главу 10)
Целое_Записать(2*j + 1, 6)
INC(w[k].count)
9.3 Последовательность предписаний Последовательности предписаний обозначают последовательность действий, заданную частями операторов, разделенными точкой с запятой.
Последовательность_Предписаний = Предписание{";" Предписание}.
9.4 Предписание IF
Предписание_IF = IF Выражение THEN
Последовательность_Предписаний
{ELSIF Выражение THEN
Последовательность_Предписаний}
[ELSE
Последовательность_Предписаний]
END.
Составное предписание IF определяет условное выполнение охраняемых подчинённых предписаний. Логическое выражение, предшествующее предписанию называется охрана. Охрана вычисляет выражение в порядке встречи, пока выражение имеет значение TRUE, после чего выполняется связанная с охраной последовательность предписаний. Если охраны не выполнена, то выполняется последовательность предписаний после символа ELSE, если такая ветка существует. Пример:
IF (литера >= "A") & (литера <= "Z") THEN
Сущность_Читать
ELSIF (литера >= "0") & (литера <= "9") THEN
Число_Читать
ELSIF литера = 22X THEN
Строку_Читать
END
9.5 Предписание CASE Составное предписание CASE определяет выбор и выполнение последовательности предписаний в соответствии со значением выражения. Сначала вычисляется выражение CASE, затем выполняется последовательность предписаний, чей список меток содержит полученное значение. Если выражение CASE имеет тип INTEGER или CHAR, все метки должны быть целыми или однолитерными строками, соответственно. Предписание_CASE= CASE выражение OF выбор{"|" выбор} END. выбор = [СписокМеток_CASE ":" ПоследовательностьПредписаний]. СписокМеток_CASE = МеткиДляВыбора{"," МеткиДляВыбора}. МеткиДляВыбора = Метка[".." Метка]. Метка = целое | строка | квалификатор.
Пример: CASE k OF 0: x := x + y | 1: x := x − y | 2: x := x * y | 3: x := x / y END
Тип T выражения CASE (CASE переменная) также может быть типом записи или ссылки. Тогда метки CASE должны быть расширениями Т, а в предписаниях Si, помеченных Ti, переменная Case рассматривается как тип Ti. Пример: TYPE тЗапись = RECORD a : INTEGER END;
R0 = RECORD (тЗапись) b: INTEGER END;
R1 = RECORD (тЗапись)
b: REAL END;
R2 = RECORD (тЗапись)
b: SET END;
P = POINTER TO тЗапись;
P0 = POINTER TO R0;
P1 = POINTER TO R1;
P2 = POINTER TO R2;
VAR p: P;
CASE p OF P0: p.b := 10 | | P1: p.b := 2.5 | | P2: p.b := {0, 2} END
9.6 Предписание WHILE Составное предписание WHILE определяет повторение. Если любое из булевых выражений (охрана) дает TRUE, выполняется соответствующая последовательность предписаний. Вычисление выражения и выполнение предписаний повторяются до тех пор, пока ни одно из булевых выражений не даст TRUE. Предписание_WHILE = WHILE Выражение DO ПоследовательностьПредписаний {ELSIF Выражение DO ПоследовательностьПредписаний} END.
Пример: WHILE j > 0 DO j := j DIV 2; i := i+1 END WHILE (t # NIL) & (t.key # i) DO t := t.left END WHILE m > n DO m := m – n ELSIF n > m DO n := n – m END
9.7 Предписание REPEAT Составное предписание REPEAT указывает повторное выполнение последовательности предписаний до тех пор, пока условие не будет выполнено. Последовательность предписаний выполняется хотя бы один раз. Предписание_Repeat = REPEAT ПоследовательностьПредписаний UNTIL Выражение.
9.8 Предписание FOR Составное предписание FOR указывает повторное выполнение последовательности предписаний заданное количество раз, одновременно последовательно увеличивая значение переменной, которая называется управляющая переменная для предписания FOR. Предписание_For = FOR Имя ":=" Выражение TO Выражение[BY КонстантаВаражения] DO ПоследовательностьПредписаний END.
Предписание FOR FOR v := beg TO end BYinc DO S END
есть, если inc>0, что эквивалентно v := beg; WHILE v <= end DO S; v := v + inc END
и если inc<0, то это эквивалентно v := beg; WHILE v >= end DO S; v := v + inc END
Типы v, beg и end должны быть INTEGER, а inc должен быть целым (константное выражение). Если шаг не указан, предполагается, что он равен 1.
10.1 Формальные параметры Формальные параметры (или просто параметры) -- это имена, которые обозначают фактические параметры (аргументы), указанные в вызове процедуры. Соответствие между аргументами и параметрами устанавливается при вызове процедуры. Существует два типа параметров, а именно переменные и значения. Переменная соответствует фактическому параметру, который является переменной, и она обозначает эту переменную. Значение соответствует фактическому параметру, который является выражением, и он обозначает его значение, которое невозможно изменить при передаче. Однако, если значение имеет базовый тип, он представляет собой локальную переменную, которой первоначально присваивается значение фактического выражения. Тип параметра указывается в списке формальных параметров: переменные обозначаются ключевым словом VAR, а значения не имеют такого префикса. Функция-процедура без параметров должна иметь пустой список параметров. Она должна быть вызвана через имя функции, список фактических параметров которой также пуст. Формальные параметры являются локальными для процедуры, т. е. их область действия - это текст программы, который представляет собой объявление процедуры. Формальныйпараметр = "(" [Секция_FP {";" Секция_FP}] ")" [":" квалификатор]. Секция_FP = [VAR] имя{"," имя} ":" ФормальныйПараметр. ФормальныйПараметр = {ARRAY OF} квалификатор. Тип каждого формального параметра указан в списке параметров. Для переменных он должен быть идентичен типу соответствующего фактического параметра, за исключением случаев записи, где он должен быть базовым типом соответствующего типа фактического параметра. Если тип формального параметра указан как ARRAY OF T параметр называется открытым массивом, а соответствующий фактический параметр может быть произвольной длины. Если формальный параметр указывает тип процедуры, то соответствующий фактический параметр должен быть либо объявленный глобально, либо переменной (или значением) этого типа процедуры. Это не может быть встроенная процедура. Тип результата процедуры не может быть ни записью, ни массивом. Примеры объявлений процедур: PROCEDURE Целое_Читать(VAR x: INTEGER); VAR i : INTEGER; ch: CHAR; BEGIN i := 0; Read(ch); WHILE ("0" <= ch) & (ch <= "9") DO i := 10i + (ORD(ch)-ORD("0")); Read(ch) END; x := i END Целое_Читать PROCEDURE Целое_Писать(x: INTEGER); ( 0 <= x < 10^5 *) VAR i: INTEGER; buf: ARRAY 5 OF INTEGER; BEGIN i := 0; REPEAT buf[i] := x MOD 10; x := x DIV 10; INC(i) UNTIL x = 0; REPEAT DEC(i); Write(CHR(buf[i] + ORD("0"))) UNTIL i = 0 END Целое_Писать
PROCEDURE log2(x: INTEGER): INTEGER; VAR y: INTEGER; (assume x>0) BEGIN y := 0; WHILE x > 1 DO x := x DIV 2; INC(y) END ; RETURN y END log2
10.2. Встроенные процедуры В следующей таблице перечислены предопределенные процедуры. Некоторые из них являются общими процедурами, то есть они применяются к нескольким типам операндов. v обозначает переменную, x и n для выражений, T - тип. Процедуры-функции: Имя Тип аргумента Тип результата Функция ABS(x) x: числовой тип соответствует типу x абсолютное значение числа ODD(x) x: INTEGER BOOLEAN x MOD 2 = 1 LEN(v) v: ARRAY INTEGER длина v LSL(x, n) x, n: INTEGER INTEGER логический сдвиг влево, x * 2n ASR(x, n) x, n: INTEGER INTEGER знаковый сдвиг вправо, x DIV 2n ROR(x, n) x, n: INTEGER INTEGER x сдвигается вправо на n бит
Функции преобразования типов: Имя Тип аргумента Тип результата Функция FLOOR(x) REAL INTEGER округление вниз FLT(x) INTEGER REAL преобразование типа ORD(x) CHAR, BOOLEAN, SET INTEGER порядковый номер x CHR(x) INTEGER CHAR литера по порядковому номеру x
Безопасные процедуры: Имя Тип аргумента Функция INC(v) INTEGER v := v + 1 INC(v, n) INTEGER v := v + n DEC(v) INTEGER v := v - 1 DEC(v, n) INTEGER v := v - n INCL(v, x) v: SET; x: INTEGER v := v + {x} EXCL(v, x) v: SET; x: INTEGER v := v - {x} NEW(v) тип ссылки размещение v^ ASSERT(b) BOOLEAN прервать, если ~b PACK(x, n) REAL; INTEGER упаковать x и n в x UNPK(x, n) REAL; INTEGER распаковать x в x и n
Функция FLOOR (x) дает наибольшее целое число, не большее x. FLOOR(1.5) = 1 FLOOR(-1.5) = -2 Параметр n в PACK представляет экспоненту x.PACK (x, y) эквивалентен x: = x * 2y UNPK - это обратная операция. Получаемый x нормализуется, так что 1.0 <= x <2.0.
В списке импорта указаны модули, для которых текущий модуль является клиентом. Если имя x экспортируется из модуля M, и если M указан в списке импорта модуля, тогда к x обращаются как M.x. Если в списке импорта используется форма «M: = M1», экспортируемый объект x, объявленный в M1, ссылается в импортируемом модуле как M.x. Имена, которые должны быть видны в клиентских модулях, то есть должны быть экспортированы, должны быть отмечены звездочкой (отметкой экспорта) в их объявлении. Переменные всегда экспортируются в режиме только для чтения. Последовательность предписаний, следующая за ключевым словом BEGIN, выполняется, когда модуль добавляется в систему (загружается). Последующие индивидуальные (без параметров) процедуры могут быть активированы из системы, и эти процедуры служат в качестве команд. Пример: MODULE Вывод; (экспортирует процедуры: Write, WriteInt, WriteLn) IMPORT Текст, Oberon; VAR W: Текст.Writer; PROCEDURE Write*(ch: CHAR);
BEGIN
Текст.Write(W, ch)
END ;
PROCEDURE WriteInt*(x, n: INTEGER); VAR i: INTEGER; a: ARRAY 16 OF CHAR; BEGIN i := 0; IF x < 0 THEN Текст.Текст(W, "-"); x := -x END ; REPEAT a[i] := CHR(x MOD 10 + ORD("0")); x := x DIV 10; INC(i) UNTIL x = 0;
REPEAT
Текст.Write(W, " "); DEC(n) UNTIL n <= i;
REPEAT
DEC(i); Текст.Write(W, a[i]) UNTIL i = 0
END WriteInt;
PROCEDURE WriteLn*;
BEGIN
Текст.WriteLn(W); Текст.Append(Oberon.Log, W.buf) END WriteLn;
BEGIN Текст.OpenWriter(W) END Out.
11.1 Модуль SYSTEM Необязательный модуль SYSTEM содержит определения, необходимые для программирования операций низкого уровня, ссылающихся непосредственно на ресурсы, специфичные для данного компьютера и/или реализации языка/компьютера. К ним относятся, например, средства доступа к устройствам, которые контролируются компьютером, и, возможно, низкоуровневым средствам для нарушения правил совместимости типов данных (иначе пришлось бы такие средства языка вводить явно). В модуле SYSTEM есть две причины для упрощения процедур: 1) Их значение зависит от реализации, то есть значение не выводится из определения языка, и 2) они могут повредить систему (например, PUT). Настоятельно рекомендуется ограничить их использование конкретными низкоуровневыми модулями, поскольку такие модули по своей сути являются не переносимыми, и не «безопасными по типу». Однако они легко распознаются из-за идентификатора SYSTEM, появляющегося в списках импорта модуля. Следующие определения обычно применимы без дополнительных изменений. Однако отдельные реализации языка могут включать в свои модули дополнительные определения SYSTEM, которые относятся к конкретному, находящемуся в использовании компьютеру. В дальнейшем v обозначает переменную, x, a и n для выражений.
Процедуры-функции: Имя Тип аргумента Тип результата Функция ADR(v) любой INTEGER адрес переменной v SIZE(T) любой тип INTEGER размер в байтах BIT(a, n) a, n: INTEGER BOOLEAN n бит в mem[a]
Собственные процедуры: Имя Тип аргумента Тип результата Функция GET(a, v) a: INTEGER; v: любой базовый тип v := mem[a] PUT(a, x) a: INTEGER; x: любой базовый тип mem[a] := x COPY(src, dst, n) все
INTEGER
копировать n последовательных слов из src в dst
Ниже приводятся дополнительные процедуры, принятые компилятором для RISC-процессора:
Процедуры-функции: Имя Тип аргумента Тип результата Функция VAL(T, n) скалярный T преобразование ADC(m, n) INTEGER INTEGER сложение с флагом переноса C SBC(m, n) INTEGER INTEGER вычитание с флагом переноса C UML(m, n) INTEGER INTEGER беззнаковое умножение COND(n) INTEGER BOOLEAN IF Cond(n) THEN ...
Собственные процедуры: Имя Тип аргумента Функция LED(n) INTEGER отображает n на LED-экране
Приложение: Синтаксис Оберона литера = "A" | "B" | … | "Z" | "a" | "b" | … | "z". цифра = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9". шестнЦифра = digit | "A" | "B" | "C" | "D" | "E" | "F". имя = литера {литера | цифра}. квалификатор = [имя "."] имя. ОпрИмени = имя [""]. целое = цифра {цифра} | цифра {шестнЦифра} "H". вещественное = цифра{цифра} "." {цифра} [экспонента]. экспонента = "E" ["+" | "-"] цифра{цифра}. число = целое | вещественное. строка = """ {литера} """ | цифра {шестнЦифра } "X". ОпрКонстанты = ОпрКонстанты "=" КонстВыражение. КонстВыражение = выражение. ОпрТипа = ОпрИмени "=" тип. тип = квалификатор| ТипМассива | ТипЗаписи | ТипСсылка | ТипПроцедуры. ТипМассива = ARRAY длина {"," длина} OF тип. длина = КонстВыражение . ТипЗаписи = RECORD ["(" БазовыйТип ")"] [ПоследСписокПолей] END. БазовыйТип = квалификатор. ПоследСписокПолей = СписокПолей {";" СписокПолей }. СписокПолей = СписокИмён ":" тип. СписокИмён = ОпрИмени{"," ОпрИмени}. ТипСсылка = POINTER TO тип. ТипПроцедуры = PROCEDURE [ФормальныеПараметры]. ОпрПеременных = СписокИмён ":" тип. выражение = ПростоеВыражение [отношение ПростоеВыражение ]. отношение = "=" | "#" | "<" | "<=" | ">" | ">=" | IN | IS. ПростоеВыражение = ["+" | "-"] разделитель {ОперАддикции разделитель }. ОперАддикции = "+" | "-" | OR. разделитель = множитель {ОперМультипликации множитель}. ОперМультипликации = "" | "/" | DIV | MOD | "&". множитель = число | строка | NIL | TRUE | FALSE | set | ссылка [АктуальныеПараметры] | "(" выражение")" | "~" множитель. ссылка = квалификатор {селектор}. селектор = "." имя| "[" СписокВыражений"]" | "^" | "(" квалификатор")". набор = "{" [элемент {"," элемент}] "}". элемент = выражение [".." выражение ]. СписокВыражений = выражение {"," выражение }. АктуальныеПараметры = "(" [СписокВыражений ] ")" . предписание = [присвоение | ВызовПроцедуры| Предписание_If | Предписание_Case | Предписание_While| Предписание_Repeat | Предписание_For].
присвоение = ссылка ":=" выражение. ВызовПроцедуры = ссылка [АктуальныеПараметры]. ПоследПредписаний = предписание {";" предписание }. Предписание_If = IF выражение THEN ПоследПредписаний {ELSIF выражение THEN ПоследПредписаний } [ELSE ПоследПредписаний ] END. Предписание_Case = CASE выражение OF вариант {"|" вариант } END. вариант = [СписокМеток_Case ":" ПоследПредписаний ]. СписокМеток_Case = СписокМеток {"," СписокМеток }. СписокМеток = метка [".." метка ]. метка = целое | строка | квалификатор . Предписание_While = WHILE выражение DO ПоследПредписаний {ELSIF выражение DO ПоследПредписаний } END. Предписание_Repeat = REPEAT ПоследПредписаний UNTIL выражение .
Предписание_For = FOR имя ":=" выражение TO выражение [BY КонстВыражение ] DO ПоследПредписаний END.
ОпрПроцедуры = ЗаголовокПроцедуры ";" ТелоПроцедуры имя. ЗаголовокПроцедуры = PROCEDURE ОпрИмени [ФормальныеПараметры].
ТелоПроцедуры = ПоследОпределений[BEGIN ПоследПредписаний ] [RETURN выражение ] END.
ПоследОпределений = [CONST {ОпрКонстант ";"}] [TYPE {ОпрТипа ";"}] [VAR {ОпрПеременной ";"}] {ОпрПроцедуры ";"}. ФормальныеПараметры = "(" [Секция_FP {";" Секция_FP}] ")" [":" квалификатор]. Секция_FP = [VAR] имя {"," имя } ":" ФормальныйТип. ФормальныйТип = {ARRAY OF} квалификатор.
модуль = MODULE имя ";" [СписокИмпорта] ПоследОпределений [BEGIN ПоследПредписаний ] END имя "."
СписокИмпорта = IMPORT импорт {"," импорт } ";". импорт = имя [":=" имя].
Использован перевод:
Свердлова С., Бурцева В.
Перевод выполнили: Денисов И. Шипков В.
Технические консультанты:
Ершов А. П. Волков С. Ермаков И. Ефимов А.
Дополнительные материалы: Чек-лист создателям компилятора