Язык программирования Оберон-У
|
|
2 vuotta sitten | |
|---|---|---|
| doc | 2 vuotta sitten | |
| LICENSE | 2 vuotta sitten | |
| README.md | 2 vuotta sitten |
Сообщение о языке Оберон-У (Оберон-Умелый, Oberon-Deft)
Ревизия: v0.0.2 / 2023-08-01
Все должно быть сделано максимально просто, но не примитивно. (А. Эйнштейн)
Идея создания языка Оберон-У (далее просто Оберон) родилась после переосмысления идей несоответствия современного ИТ и средств разработки. Никлаус Вирт продвинулся в этом отношении дальше всех. И львиная доля идей в концепции Оберон является либо трансляцией этих идей, либо творческой компиляции их.
Оберон-У — язык программирования общего назначения, который является развитием Модулы-2 и модификацией Оберон-7.
Данная вариация по большей части не имеет принципиально новых концепций, новые части отдельно описаны в соответствующих разделах. Концепция позволяет максимально изолировать высокоуровневые средства от низкоуровневых.
Назначение этого документа в том, чтобы служить эталоном для программистов, разработчиков и авторов руководств. Если о чём-то не сказано, то обычно это ошибка.
Этот документ описывает язык как достаточный для реализации различного рода ПО: начиная от загрузчиков ОС, сами ОС системное и прикладное ПО.
Для описания синтаксиса используется диалект расширенной формы Бэкуса—Наура (РБНФ) -- НШ краткая справка. Литера вопроса ? означают необязательность записанного внутри них выражения, а двоеточие .. означают его повторение (возможно 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\"!"
Все символы делятся на две группы:
встроенные символы (предопределены заранее);пользовательские символы (определяются пользователем).В группу встроенных символов входят:
ключевой символ (зарезервированные слова);предписание (сложные сущности, управляющие потоком программы);оператор (простые сущности ,управляющие действиями);разделитель (простые сущности, разделяющие другие сущности).Ключевые символы являются специальной группой и они не могут использоваться в качестве пользовательских символов ни в какой части программы.
Группа символов комментарии могут быть вставлены между любыми двумя символами в программе. Они являются произвольными последовательностями литер, которые открываются /*, (* и закрываются с помощью */, *). Однострочные комментарииначинаются на//` и действуют до конца строки. Комментарии не влияют на смысл программы. Они могут быть вложенными.
Разделитель включает в себя:
пробел;перенос строки.Для более полного понимания зависимостей ниже приводится структурная схема:
flowchart TD
Программа
Модуль0
Модуль1
Сущность0
Сущность1
Пользовательские_символы
Встроенные_символы
Имя
Литеры
Программа --> Модуль0
Программа --> Модуль1
Модуль1 --> Сущность0
Модуль1 --> Сущность1
Сущность1 --> Пользовательские_символы
Сущность1 --> Встроенные_символы
Встроенные_символы --> Ключевые_символы
Встроенные_символы --> Предписания
Встроенные_символы --> Операторы
Встроенные_символы --> Разделители
Пользовательские_символы --> Имя
Ключевые_символы --> Имя
Предписания --> Имя
Имя --> Литеры
Операторы --> Литеры
Разделители --> Литеры
Литеры --> Буквы
Литеры --> Цифры
Литеры --> Служебные
Цифры --> Целые
Цифры --> Дробные
Ниже перечислен полный список ключевых символов
| Символ | Комментарий |
|---|---|
| + | Сложение |
| ++ | Инкремент операнда |
| += | Сложение операндов с присвоением операнду слева |
| = | Присвоение |
| - | Минус |
| -- | Декремент |
| -= | Вычитание операндов, с присвоением операнду слева |
| ^ | Исключающее ИЛИ |
| ^= | Исключающее ИЛИ с присвоением операнды слева |
| * | Умножение |
| ** | Возведение в степень |
| **= | Возведение в степень с присвоением операнда слева |
| / | Деление |
| /= | Деление с присвоением операнду слева |
| ~ | Отрицание |
| < | Меньше |
| > | Больше |
| & | Логическое И |
| &= | Логическое И с присвоением операнду слева |
| = | Присвоить |
| // | Линейный комментарий |
| /* | Начало многострочного комментария |
| */ | Конец многострочного комментария |
| (* | Начало многострочного комментария |
| *) | Конец многострочного комментария |
| . | Точка |
| <= | Меньше или равно |
| , | Запятая |
| >= | Больше или равно |
| ; | Точка с запятой |
| ... | Перечисление |
| | | Логическое ИЛИ |
| : | Определить тип переменной |
| ( | Открывающая круглая скобка (выражение) |
| ) | Закрывающая круглая скобка (выражение) |
| [ | Открывающая квадратная скобка (массив) |
| ] | Закрывающая квадратная скобка (массив) |
| { | Фигурная открывающая скобка (область видимости) |
| } | Закрывающая фигурная скобка (область видимости) |
| ЕСТЬ | IS Проверка типа |
| БУЛ | BOOL Белвый тип |
| ДА | TRUE Булево значение |
| НЕТ | FALSE Отрицание логического значения |
| БАЙТ | BYTE Тип байт |
| ЦЕЛОЕ | INT Дробное число |
| ВЕЩ | REAL Дробное число |
| МАССИВ | ARRAY Массив элементов |
| ПРОВЕР | SWITCH Проверка на выбор |
| ТИП | TYPE Объявление типа |
| МОДУЛЬ | MODULE Объявление начала модуля |
| ИМПОРТ | IMPORT Импорт модуля |
| КОНСТ | CONST Объявление константы |
| ТИП | TYPE Определение типа |
| СТРУКТ | STRUCT Объявление структуры |
| ЗНАЧ | VAR Объявление переменной |
| МУТ | MUT Признак изменяемости |
| ФН | FN Объявление функции |
| ВЕРНУТЬ | RETURN Возврат из функции |
| НОВ | NEW Создать новую переменную |
| ЕСЛИ | IF Начало условия |
| АЕСЛИ | IF Альтернативноее, если предыдущее не сработало |
| МОД | MOD Модуль от целочисленного деления |
| ДИВ | DIV Остаток от целочисленного деления |
| НИЧ | NIL Пустое состояние объекта |
| ПОКА | WHILE Условие проверки продолжения цикла на входе |
| ПЕТЛЯ | LOOP Бесконечный цикл |
| ДАЛЬШЕ | NEXT Продолжить цикл с пропуском следующих выражений |
| ПРЕРВАТЬ | BREAK Прервать цикл с пропуском следующих выражений |
| ИЛИ | OR Логическое ИЛИ |
| И | AND Логическое И |
| НЕ | NOT Логическая инверсия |
| ДЛЯ | FOR Объявление цикла |
Каждое встречающееся в программе имя должно быть объявлено заранее, если это ключевой символ (например, ТИП или ПЕРЕМ). Имя также служит для задания опредёленных постоянных свойств сущности, например, является ли оно константой, определением типа, переменной или функцией.
Имя используется для ссылки на соответствующую сущность. Это возможно в тех частях программы, которые находятся в пределах области видимости. Имя не может обозначать больше чем одну сущность внутри данной области. Область видимости распространяется текстуально от точки объявления до конца блока (функции или модуля), к которому принадлежит имя и, следовательно -- по отношению к которому, объект является локальным.
Имя, объявленное в блоке модуля, может сопровождаться меткой экспорта сразу после имени * , чтобы пояснить, что оно экспортируется из определяющего модуля с доступом только на чтение. В этом случае имя может быть использовано и в других модулях, если эти модули импортируют объявляющий модуль.
Имя символа предваряется другим именем (префиксом), показывающим его модуль (см. Гл 11). Префикс и имя разделены точкой и вместе называются уточнённым именем (или квалифицированным именем).
ИмяКвал = имя + "." + имя; ИмяЭкспорт = имя + "*";
Следующие имена являются стандартными (группа ключевые символы); их значение определено ниже:
ASR ASSERT БУЛ БАЙТ EXCL FLT ЦЕЛОЕ LSL НОВ ODD ORD PACK ВЕЩ ROR SET UNPK
Объявление константы связывает её имя с её значением.
КонстантноеВыражение = Выражение; ОбъявлениеКонстанты = ИмяОпр "=" КонстантноеВыражение;
Константное выражение может быть вычислено по его тексту без фактического выполнения программы. Его операнды — константы. Примеры объявлений констант:
КОНСТ {
число = 100,
лимит = 2 * число - 1,
словаВсе = [0 .. словаРазмер -1],
имя = "Oberon",
}
Тип данных задаёт множество специфичных значений, которые переменные этого типа могут принимать, а также множетво операторов и методов, которые к ним применимы. Объявление типа используется для связывания имени с типом. Типы определяют структуру переменных этого типа и, косвенно, операторы, которые применимы к компонентам самих типов.
Типы данных деляется на две группы:
В группе встроенных типов также есть деление на две части:
После присвоения литеральная строка представлена массивом байтов.
ОбъявлениеТипа = ИмяОпр "=" Тип. Тип = ИмяКвал | ТипМассив | ТипЗапись | ТипСсылка | ПроцедурныйТип.
Примеры:
ТИП {
Таблица = МАССИВ[255]ВЕЩ,
Дерево = Узел,
СТРУКТ Узел {
ключ: ЦЕЛОЕ,
Левый, Правый: Дерево,
}
ДеревоСередина = УзелСередина,
СТРУКТ УзелСередина (Узел){
Имя: МАССИВ[32]БАЙТ,
Подузел: Дерево,
}
Функция = FN (x: ЦЕЛОЕ): ЦЕЛОЕ,
}
Встроенные операторы и встроенные функции определены ниже. Имена встроенных типов следующие:
Встроенные линейные типы:
БУЛ -- принимает значения TRUE и FALSEБАЙТ -- целые числа от 0 до 255, размер фиксированный в 8 битЦЕЛОЕ -- целые числа, размер зависит от реализацииВЕЩ -- дробные числа, размер зависит от реализацииТип БАЙТ совместим с типом ЦЕЛОЕ, но наоборот требуется прведение.
Тип ЦЕЛОЕ совместим с типом ВЕЩ, но наоборот требуется прведение.
В любом случае приведение всегда выполняется явно.
В группе векторных типов есть два типа:
Массив - это структура, состоящая из фиксированного количества элементов, тип элементов одинаковый для всех элементов данного типа массива. Количество элементов массива называется его длиной. Элементы массива обозначаются индексами, которые являются целыми числами от 0 до (длины - 1).
ТипМассива = МАССИВ[длина, длина..?]тип_элемента;
длина = Выражение | КонстантноеВыражение;
Форма объявления
МАССИВ[N0, N1, ..., Nk]T
Примеры типов массивов:
ЗНАЧ {
listUser=МАССИВ[NN]ЦЕЛОЕ,
moments=МАССИВ[10, 20]ВЕЩ,
}
Литеральная строка при создании представляет собой набор байт в виде букв в двойных кавычках. После привоения фактически -- это массив байт.
Пример:
ЗНАЧ {
strHello="Привет",
}
Все встроенные векторные типы всегда передаются по ссылке.
Сущность структура, состоящая из фиксированного количества элементов возможно разных типов. Объявление типа структуры задаёт для каждого элемента, которое называется полем, его тип и имя, которое првязывает это поле. Область действия этих имён полей - само определение структуры, но они также видны как неотъемлемые части экземпляра структуры в форме "через точку", которая ссылается на элементы самого экземпляра структуры.
ТипЗаписи = СТРУКТ ( БазовыйТип?) {
СписокПолейТипа
};
БазовыйТип = квалификатор;
СписокПолейТипа= СписокПолей?;
СписокПолей = Поле..?
Поле = Имя, Имя..? ":" тип;
Если тип структуры экспортируется, имена полей, которые должны быть видимыми вне модуля объявления, должны быть помечены. Они называются публичными полями; неотмеченные поля называются приватными полями. Типы записей являются расширяемыми, т. е. тип записи может быть определён как расширение другого типа записи. В приведенных выше примерах УзелСередина (непосредственно) расширяет Узел, который является (прямым) базовым типом УзелСередина. Точнее, УзелСередина расширяет Узел с полями имя и подузел.
Определение. Тип T1 является T0, если он непосредственно расширяет T0. И наоборот, тип T0 является базовым типом для типа T1, если он является прямым базовым типом базового типа T1. Примеры типов структур:
ТИП {
СТРУКТ Дата {
день, месяц, год: ЦЕЛОЕ,
}
СТРУКТ User (Дата){
имя, фамилия: МАССИВ[32]БАЙТ,
возраст: ЦЕЛОЕ,
зарплата: ВЕЩ,
}
}
Типы структур всегда связываются по ссылке.
Тип = Структура?;
Тип функции является объектом кода, поэтому функция является статической сущностью.
Все переменные присваиваются ссылкой на функцию.
ТипФункция = FN (ФормальныеПараметры?)Результат?;
Объявления переменных служат для введения переменных и связывания их с именами, которые не должны повторяться в пределах данной области видимости. Они также служат для связывания встроенных линейных типов данных с переменными.
ОбъявлениеПеременной = СписокИмён ":" тип;
Переменные, имена которых отображаются через запятую имеют один и тот же тип. Примеры объявления переменных (см. Примеры в главе 6):
ТИП {
СТРУКТ Текст {
лит: БАЙТ,
счётчик: ЦЕЛОЕ,
}
}
ЗНАЧ {
i, j, k: ЦЕЛОЕ,
x, y: ВЕЩ,
p, q: БУЛ,
f: FN(),
a: МАССИВ[100]ВЕЩ,
w: МАССИВ[16]Текст,
t: Дерево,
}
Выражения - это конструкции, содержащие правила вычисления, в которых константы и текущие значения переменных объединяются для получения других значений посредством применения операторов и процедур возвращающих результат.
Выражения состоят из операндов и операторов. Также могут включать круглые скобки для выражения определённых правил вычисления операторов и операндов. Выражения разделяются ;
За исключением чисел и литерных констант, операнды обозначаются именами. Обозначение операнда состоит из имени, которое может оносится к сущностям:
Если имя операнда определено как имя модуля, то за ним могут следовать имена подчинённых сущностей. Если операнд является структурой, то через точку указываются поля такой структуры.
селектор = "." Имя | "["СписокВыражения"]" | «^» | "(" Квалификатор ")"; СписокВыражения = выражение..?;
Если обозначенное имя сущности является переменной, то имя переменной ссылается на текущее значение переменной.
Если объект является функцией, то имя функции без списка параметров ссылается на эту функцию. Если за функцией следует список параметров (возможно, пустой), имя подразумевает вызов функции и обозначает значение, полученное в результате её выполнения. Фактические параметры (используемых типов) должны соответствовать формальным параметрам, указанным в объявлении функции (см. далее).
Примеры обозначений (см. Примеры в главе 7):
i (ЦЕЛОЕ)
а[I] (ВЕЩ)
w[3].ch (БАЙТ)
t.ключ (ЦЕЛОЕ)
t.левый.правый (Дерево)
t(УзелСредний).подузел(Дерево)
Синтаксис выражений различает четыре вида операторов с разными приоритетами (порядком выполнения).
~ (инверсия имеет наивысший приоритет)*, / (умножение и деление)+,- (сложения и вычитание)Операции одного и того же приоритета выполняются слева направо. Например,
x-y-z
означает
(x-y)-z
выражение = (ОперацияПростая ОперацияОтношение ОперацияПростая)..;
ОперацияОтношение = "=" | "~" | "<" | "<=" | ">" | ">=" | ЕСТЬ;
ОперацияПростая = ()"+"|"−"? разделитель? ОператорАддикции разделитель?;
ОперациярАддикции= "+" | "−" | ИЛИ;
разделитель = множитель ОператорМультипликации? множитель;
ОператорМультипликации = "*" | "/" | ДИВ | МОД | И;
множитель = число| строка| ПУСТО | ДА | НЕТ | ФактическийПараметр.. | "(" выражение ")" | "~" множитель;
ОперацияВыборки = выражение выражение..?;
ФактическийПараметр = ( СписокВыражения..?);
Множество [m..n] обозначает [m, m + 1, ..., n-1, n], а если m>n, то пустое множество. Доступные операции перечислены в следующих таблицах. В некоторых случаях несколько разных операций обозначаются одним и тем же символом операции. В этих случаях фактическая операция определяется типом операндов.
| Символ | Результат |
|---|---|
| ИЛИ | OR логическая дизъюнкция |
| И | И логическое соединение |
| НЕ | НЕ логическое отрицание |
Эти операции применяются к операндам БУЛ и дают результат BOO.
р ИЛИ q // означает «если р, то ДА, иначе q» p И q // обозначает «если р, то q, иначе НЕТ НЕ P // означает "не p"
| Символ | Результат |
|---|---|
| + | сложение |
| - | вычитание |
| * | умножение |
| / | деление |
| ДИВ | целое частное от деления |
| МОД | целое модуль от деления |
Операторы +, -, * и / применяются к операндам числовых типов. Оба операнда должны быть одного типа, что также определяет тип результата. При использовании в качестве унарных операторов:
- обозначает инверсию знака;+ обозначает оператор идентичности.Операции DIV и MOD применяются только к целочисленным операндам. Пусть q = x ДИВ y, а r = x МОД y. Тогда множитель q и остаток r определяются уравнением:
x = q * y + r 0 <= r < y
| Символ | Результат |
|---|---|
| = | равно |
| != | неравно |
| < | меньше |
| <= | меньше или равно |
| > | больше |
| = | больше или равно |
| ЕСТЬ | проверка типа |
Результат операций отношения является базовым типом БУЛ. ОперацияОтношение (<, <=,>,=) применяется к числовым типам и БАЙТ. Отношения = и != применимы также к типам БУЛ, ссылкам и процедурным типам.
v ЕСТЬ T означает v ЯВЛЯЕТСЯ типом T и вызывает проверку типа. Это применимо, если выполнены все условия:
T расширение объявленной структуры T0 для v;v параметр, как переменная заданного типа структуры.Предполагая, например, что сслыка на тип структуры T является расширением базовой ссылки на тип структуры T0, тогда проверка v ЕСТЬ T определяет, является ли фактически указанная переменная (в том числе, а не только T0) cтруктурой типа T. Значение ПУСТО ЕСТЬ Т возвращает отрицательный результат.
Примеры выражений (см. Примеры в главе 7):
1987 (`ЦЕЛОЕ`)
I ДИВ 3 (`ЦЕЛОЕ`)
~ P ИЛИ q (`БУЛ`)
(I + j) * (i-j) (`ЦЕЛОЕ`)
A [i + j] * a [i-j] (`ВЕЩ`)
(0 <= i) & (i <100) (`БУЛ`)
T.ключ = 0 (`БУЛ`)
K == i (`БУЛ`)
T ЕСТЬ УзелСредний (`БУЛ`)
Предписания обозначают языковые действия. Есть простые и составные предписания. Простые предписания не состоят из каких-либо частей, которые сами являлись бы предписаниями. Простые предписания -- просто присваивания, либо вызов процедур.
Составные предписания состоят из частей, которые сами являются предписаниями. Они используются, чтобы выразить последовательное и условное, выборочное и повторное действие.
Предписания также могут быть пустыми, и в этом случае они не обозначают никаких действий. Пустое предписание включено в язык для того, чтобы ослабить правила пунктуации в последовательностях предписаний.
Предписание = [Присвоение | ВызовПроцедур | Предписание_ЕСЛИ | Предписание_ВЫБОР | Предписание_ПОКА | Предписание_ДЛЯ | Предписание_ПЕТЛЯ].
Элементарное предписание ПРИСВОЕНИЕ служит для замены текущего значения переменной на новое значение, заданное выражением. Предписание ПРИСВОЕНИЕ записывается как «=» и произносится как «присвоить».
присвоение = переменная "=" выражение.
Если значение параметра обладает структурой (массив или структура), параметру не разрешено присваивать его или его элементам. Импортируемые переменные также не могут быть присвоены. Если переменная не помечена ключевым словом МУТ при её описании -- ей нельзя присваивать даже в модуле объявления (кроме случаев создания такой переменной).
Тип выражения должен быть таким же, как у переменной. Имеют место следующие исключения:
ПУСТО можно присвоить переменным любого типа;БАЙТ;Примеры присвоений (см. Примеры в главе 7):
i = 0
p = i = j
x = FLT(i + 1)
k = (i + j) ДИВ 2
f = log2
s = [2, 3, 5, 7, 11, 13]
a[i] = (x+y) * (x-y)
t.key = i
w[i+1].ch = "A"
Последовательности предписаний обозначают последовательность действий, заданную частями операторов, разделенными точкой с запятой.
Последовательность_Предписаний = Предписание? ; (Предписание;)..?;
Предписание_ЕСЛИ = ЕСЛИ Выражение {
Последовательность_Предписаний;
}АЕСЛИ Выражение {
Последовательность_Предписаний;
}
Составное предписание ЕСЛИ определяет условное выполнение охраняемых подчинённых предписаний. Логическое выражение, предшествующее предписанию называется охрана. Охрана вычисляет выражение в порядке встречи, пока выражение имеет значение ДА, после чего выполняется связанная с охраной последовательность предписаний. Если охраны не выполнена, то выполняется последовательность предписаний после символа АЕСЛИ, если такая ветка существует. Пример:
ЕСЛИ (литера >= "A") И (литера <= "Z") {
Сущность_Читать();
}АЕСЛИ (литера >= "0") И (литера <= "9") {
Число_Читать();
}АЕСЛИ литера = 22X {
Строку_Читать();
}
Составное предписание ВЫБОР определяет выбор и выполнение последовательности предписаний в соответствии со значением выражения. Сначала вычисляется выражение ВЫБОР, затем выполняется последовательность предписаний, чей список меток содержит полученное значение. Если выражение ВЫБОР имеет тип ЦЕЛОЕ или БАЙТ, все метки должны быть целыми или байтами, соответственно.
Предписание_ВЫБОР= ВЫБОР выражение СписокМеток_ВЫБОР;
Выбор = Сущность ":" СписокВыражений;
СписокМеток_ВЫБОР = МеткиДляВыбора["," МеткиДляВыбора].
МеткиДляВыбора = Метка .. Метка..?;
Метка = целое | строка | квалификатор.
Пример:
ВЫБОР k {
| 0: x = x + y,
| 1: x = x − y,
| 2: x = x * y,
| 3: x = x / y,
}
Тип T выражения ВЫБОР (переменная после ключевого символа ВЫБОР) также может быть типом структуры. Тогда метки для ВЫБОР должны быть расширениями Т, а в предписаниях Si, помеченных Ti, переменная ВЫБОР рассматривается как тип Ti.
Пример:
ТИП СвязьЦел СТРУКТ{
a : ЦЕЛОЕ
}
р0 := СвязьЦел{
а:5,
}
ТИП СвязьВещ СТРУКТ{
а:ВЕЩ
}
р1 := СвязьВещ{
а:6.1,
}
P := тЗапись{};
P0 = R0;
P1 = R1;
P2 = R2;
ВЫБОР p {
| P0: p.а = 10
| P1: p.а = 2.5
| P2: p.а = 0, 2
}
Составное предписание ПОКА определяет повторение. Если любое из булевых выражений (охрана) дает ДА, выполняется соответствующая последовательность предписаний. Вычисление выражения и выполнение предписаний повторяются до тех пор, пока в итоге булевы выражения охрыны не дадут НЕТ.
Предписание_ПОКА = ПОКА Выражение {}
ПоследовательностьПредписаний
АЕСЛИ Выражение {
ПоследовательностьПредписаний
}
Пример:
ПОКА j > 0 {
j = j ДИВ 2;
i = i+1;
}
ПОКА (t НЕ NIL) И (t.key НЕ i){
t = t.left;
}
ПОКА m > n {
m = m – n;
} АЕСЛИ n > m {
n = n – m;
}
Составное предписание ДЛЯ указывает повторное выполнение последовательности предписаний заданное количество раз, одновременно последовательно увеличивая значение переменной, которая называется управляющая переменная для предписания FOR.
Предписание_ДЛЯ =
ДЛЯ Имя ":=" Выражение ДО Выражение[ПО КонстантаВаражения]{
ПоследовательностьПредписаний
}
Предписание ДЛЯ
ДЛЯ v := beg ДО end ПО inc { S }
есть, если inc>0, что эквивалентно
v := beg;
ПОКА v <= end {
S();
v = v + inc;
}
и если inc<0, то это эквивалентно
v := beg;
ПОКА v >= end {
S();
v = v + inc;
}
Типы v, beg и end должны быть ЦЕЛОЕ, а inc должен быть целым (константное выражение). Если шаг не указан, предполагается, что он равен 1.
Объявление функцмй состоит из заголовка функции и её тела. Заголовок определяет имя функции, формальные параметры и тип результата (если таковой есть). Тело содержит объявления и предписания.
Существует два типа функций, а именно функции и фнкции-процедуры.
Первые активируются именем функции как частью выражения и возвращают результат, являющийся операндом в вызывающем выражении.
Функции-процедуры активируются вызовом функции. Функция-процедура отличается в объявлении путём указания типа её результата после списка параметров. Её тело должно заканчиваться ключевым словом ВЕРНУТЬ, которое определяет результат функции-процедуры.
Все константы, переменные и типы, объявленные в теле функции, являются локальными для этой функции. Значения локальных переменных не определены при входе в функцию.
В дополнение к своим формальным параметрам и локально объявленным объектам -- объекты, объявленные глобально, также видны в функции. Использование имени функции в вызове в границах её объявления подразумевает рекурсивный вызов функции.
ОбъявлениеФункции = ИмяФункции{ТелоФункции}.
ИмяФункции = ФН ИмяФункции(ФормальныеПараметры..)Результат.
ТелоФункции = ПоследОбъявлений{ПоследПредписаний, ВЕРНУТЬ Выражение}.
ПоследОбъявлений = [КОНСТ {ОбъявлениеКонстант ";"}]
[ТИП {ОбъявлениеТипов ";"}] [ЗНАЧ {ОбъявлениеПеременных ";"}]
{ОбъявлениеФункции ";"}.
Формальные параметры (или просто параметры) -- это имена, которые обозначают фактические параметры (аргументы), указанные в вызове функции. Соответствие между аргументами и параметрами устанавливается при вызове функции. Переменная соответствует фактическому параметру, который является переменной, и она обозначает эту переменную. Значение соответствует фактическому параметру, который является выражением, и он обозначает его значение, которое невозможно изменить при передаче. Однако, если значение имеет базовый тип, он представляет собой локальную переменную, которой первоначально присваивается значение фактического выражения.
Тип параметра указывается в списке формальных параметров: переменные обозначаются ключевым словом ЗНАЧ, а значения не имеют такого префикса.
Функция-процедура без параметров должна иметь пустой список параметров. Она должна быть вызвана через имя функции, список фактических параметров которой также пуст.
Формальные параметры являются локальными для функции, т. е. их область действия - это текст программы, который представляет собой объявление функции.
Формальныйпараметр = "(" [Секция_FP {";" Секция_FP}] ")" [":" квалификатор].
Секция_FP = [ЗНАЧ] имя{"," имя} ":" ФормальныйПараметр.
ФормальныйПараметр = МАССИВ[nn]Тип..
Тип каждого формального параметра указан в списке параметров. Для переменных он должен быть идентичен типу соответствующего фактического параметра, за исключением случаев структур, где он должен быть базовым типом соответствующего типа фактического параметра.
Если формальный параметр указывает тип функции, то соответствующий фактический параметр должен быть либо объявленный глобально, либо переменной этого типа функции. Это не может быть встроенная функция. Тип результата функции может быть любым типом, но только один.
Примеры объявлений функций:
ФН Целое_Читать(ЗНАЧ x: `ЦЕЛОЕ`){
ЗНАЧ i : ЦЕЛОЕ;
ЗНАЧ ch: БАЙТ;
i = 0;
Читать(ch);
ПОКА ("0" <= ch) И (ch <= "9") {
i = 10*i + (ORD(ch)-ORD("0"));
Читать(ch);
}
x = i
}
ФН Целое_Писать(x: ЦЕЛОЕ){ // 0 <= x < 10^5
ЗНАЧ i: ЦЕЛОЕ;
ЗНАЧ buf: МАССИВ[5]ЦЕЛОЕ;
i = 0;
ПОКА i==0{
buf[i] = x МОД 10;
x = x ДИВ 10;
i++
i++;
Записать(БАЙТ(buf[i] + ORD("0")));
}
ФН лог2(x: ЦЕЛОЕ):ЦЕЛОЕ{
ЗНАЧ y ЦЕЛОЕ = 0; // assume x>0
WHILE x > 1 {
x = x ДИВ 2;
y++;
}
ВЕРНУТЬ y
}
В следующей таблице перечислены встроенные функции. Некоторые из них являются общими функциями, то есть они применяются к нескольким типам операндов. v обозначает переменную, x и n для выражений, T - тип.
Функции-Процедуры:
| Имя | Тип аргумента | Тип результата | Описание | Англ |
|---|---|---|---|---|
| x: числовой тип | соответствует типу x | абсолютное значение числа | ABS(x) | |
| x: ЦЕЛОЕ | БУЛ | x МОД 2 = 1, чёиность | ODD(x) | |
| м.Длин() | v: МАССИВ | ЦЕЛОЕ | длина массива v | v.Len() |
| х.СдвигЛев(н) | x, н: ЦЕЛОЕ | ЦЕЛОЕ | логический сдвиг влево, x * 2n | LSL(x, n) |
| x, n: ЦЕЛОЕ | ЦЕЛОЕ | знаковый сдвиг вправо,x DIV 2n | ASR(x, n) | |
| x, n: ЦЕЛОЕ | ЦЕЛОЕ | x сдвигается вправо на n бит | ROR(x, n) |
Функции преобразования типов:
| Имя | Тип аргумента | Тип результата | Функция | Англ |
|---|---|---|---|---|
| ВЕЩ | ЦЕЛОЕ | округление вниз | FLOOR(x) | |
| ЦЕЛОЕ | ВЕЩ | преобразование типа | FLT(x) | |
| БАЙТ, БУЛ | ЦЕЛОЕ | порядковый номер x | ORD(x) |
Безопасные процедуры:
| Имя | Тип аргумента | Функция | Англ |
|---|---|---|---|
| НОВ(v) | перменная | размещение переменной в памяти | NEW(v) |
| BOOLEAN | прервать, если ~b | ASSERT(b) | |
| ВЕЩ, ЦЕЛОЕ | упаковать x и n в x | PACK(x, n) | |
| ВЕЩ, ЦЕЛОЕ | распаковать x в x и n | UNPK(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. Если в списке импорта используется форма M1 = M, экспортируемый объект x, объявленный в M1, ссылается в импортируемом модуле как M1.x.
Имена, которые должны быть видны в клиентских модулях, то есть должны быть экспортированы, должны быть отмечены звездочкой (отметкой экспорта) в их объявлении. Переменные всегда экспортируются в режиме только для чтения.
Последовательность предписаний, следующая за ключевым символом "{", выполняется, когда модуль загружается в систему. Последующие индивидуальные (без параметров) функции могут быть активированы из системы, и эти процедуры служат в качестве команд.
Пример:
МОДУЛЬ Вывод; // экспортирует процедуры: Write, WriteInt, WriteLn
ИМПОРТ {
Текст,
Oberon,
}
ЗНАЧ {
W: Текст.Writer,
}
ФН Write*(ch: БАЙТ){
Текст.Write(W, ch);
}
ФН WriteInt*(x, n: `ЦЕЛОЕ`){
ЗНАЧ {
i: ЦЕЛОЕ = 0,
a: МАССИВ[16]BYTE,
}
ЕСЛИ x < 0 {
Текст.Текст(W, "-");
x := -x;
}
ПЕТЛЯ {
a[i] = CHR(x MOD 10 + ORD("0"));
x = x DIV 10;
i++
ЕСЛИ х == 0{
ПРЕРВАТЬ;
}
}
Текст.Write(W, " ");
n--;
ПЕТЛЯ {
ЕСЛИ n >i{
ПРЕРВАТЬ;
}
i--;
}
Текст.Write(W, a[i]);
}
ФН WriteLn*{}
Текст.WriteLn(W);
Текст.Append(Oberon.Log, W.buf);
}
{
Текст.OpenWriter(W)
}
Необязательный модуль СИСТЕМА содержит определения, необходимые для программирования опасных операций, ссылающихся непосредственно на ресурсы, специфичные для данной аппаратуры.
Импорт модуля СИСТЕМА может быть пустым для обозначения опасных операций.
К опасным операциям относятся, например, средства доступа к устройствам, которые контролируются аппаратурой, и, возможно, низкоуровневым средствам для нарушения правил совместимости типов данных (иначе пришлось бы такие средства языка вводить явно).
В модуле СИСТЕМА есть две причины для упрощения процедур:
СИСТЕМА, появляющегося в списках импорта модуля.Следующие определения обычно применимы без дополнительных изменений. Однако отдельные реализации языка могут включать в свои модули дополнительные определения СИСТЕМА, которые относятся к конкретной, находящейся в использовании аппаратуре. В дальнейшем v обозначает переменную, x, a и n для выражений.
Процедуры-функции:
Имя
Тип аргумента
Тип результата
Функция
ADR(v)
любой
ЦЕЛОЕ
адрес переменной v
SIZE(T)
любой тип
ЦЕЛОЕ
размер в байтах
BIT(a, n)
a, n: ЦЕЛОЕ
BOOLEAN
n бит в mem[a]
Собственные процедуры:
Имя
Тип аргумента
Тип результата
Функция
GET(a, v)
a: ЦЕЛОЕ;
v: любой базовый тип
v := mem[a]
PUT(a, x)
a: ЦЕЛОЕ;
x: любой базовый тип
mem[a] := x
COPY(src, dst, n)
все
ЦЕЛОЕ
копировать n последовательных слов из src в dst
Ниже приводятся дополнительные процедуры, принятые компилятором для RISC-процессора:
Процедуры-функции:
Имя
Тип аргумента
Тип результата
Функция
VAL(T, n)
скалярный
T
преобразование
ADC(m, n)
ЦЕЛОЕ
ЦЕЛОЕ
сложение с флагом переноса C
SBC(m, n)
ЦЕЛОЕ
ЦЕЛОЕ
вычитание с флагом переноса C
UML(m, n)
ЦЕЛОЕ
ЦЕЛОЕ
беззнаковое умножение
COND(n)
ЦЕЛОЕ
BOOLEAN
IF Cond(n) THEN ...
Собственные процедуры:
Имя
Тип аргумента
Функция
LED(n)
ЦЕЛОЕ
отображает 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". ОпрКонстанты = ОпрКонстанты "=" КонстВыражение. КонстВыражение = выражение. ОпрТипа = ОпрИмени "=" тип. тип = квалификатор| ТипМассива | ТипЗаписи | ТипСсылка | ТипПроцедуры. ТипМассива = МАССИВ длина {"," длина} 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.
ПоследОпределений = [КОНСТ {ОпрКонстант ";"}] [TYPE {ОпрТипа ";"}] [ЗНАЧ {ОпрПеременной ";"}] {ОпрПроцедуры ";"}. ФормальныеПараметры = "(" [Секция_FP {";" Секция_FP}] ")" [":" квалификатор]. Секция_FP = [ЗНАЧ] имя {"," имя } ":" ФормальныйТип. ФормальныйТип = {МАССИВ OF} квалификатор.
модуль = MODULE имя ";" [СписокИмпорта] ПоследОпределений [BEGIN ПоследПредписаний ] END имя "."
СписокИмпорта = IMPORT импорт {"," импорт } ";". импорт = имя [":=" имя].
Использован перевод:
Свердлова С., Бурцева В.
Перевод выполнили: Денисов И. Шипков В.
Технические консультанты:
Ершов А. П. Волков С. Ермаков И. Ефимов А.
Дополнительные материалы: Чек-лист создателям компилятора