Была ли жизнь до Алгола и Фортрана? Бытует представление, что Фортран и Алгол были первыми языками, данными богом человеку, а до них ничего не было, и только святой дух витал над водами. Однако это не так, и третья глава книжки про ЭВМ "Киев" даёт нам возможность заглянуть в доисторическую эпоху, когда программирование в машинных кодах уже осточертело, а человеческие языки ещё не зародились.
Так называемый Адресный язык был придуман программистами для математиков. Или наоборот, математиками для программистов. Дело происходило в конце 50-х в Лаборатории вычислений киевского института Математики.Та самая лаборатория и та самая команда, где создавался первая советская ЭВМ МЭСМ.
МЭСМ заработала в 1951-м и продолжала активно эксплуатироваться до 1957 года. К ней мгновенно образовалась очередь математиков, желающих чего-нибудь посчитать. Известные люди, доктора и академики, у каждого своя важная народно-хозяйственная задача. И конечно, никто не смыслит в машинных кодах, и знать не желает систему команд ЭВМ. Тем более, что она секретная и нигде не описанная.
Сложилась практика, что математики присылают свои задачи программистам на своём математическом языке. То есть набор математических формул со словесными комментариями. Задачей сотрудников Лаборатории вычислений было переложить задачу на язык машины, выполнить на ЭВМ и сообщить численные результаты. Отладка программы и верификация результатов сильно затруднялась по той простой причине, что математики не имели возможности отследить правильность машинного кода. Нужна была некая промежуточная форма, понятная и математикам-постановщика задачи, и программистам-вычислителям. Так возник Адресный язык.
Поначалу ни о какой автоматической трансляции Адресного языка в машинный код речь не шла. ЭВМ была слишком слаба для такой задачи. Машинный код порождался человеком вручную, глядя в исходник на Адресном языке, и выписывая оператор за оператором. И тем не менее, это было эффективнее, чем делать это непосредственно из исходных математических формул. Только через несколько лет, в середине 60-х была поставлена задача построения транслятора Адресного языка, и частично решена для некоторых советских ЭВМ. Но к тому времени появились Алгол и Фортран, и интерес сместился. Пошла совсем другая история.
Посмотрим, как выглядел Адресный язык. Я буду стараться использовать термины из оригинального описания языка, и показывать аналогию с современностью (в основном Си).
Программа представляет собой последовательность строк. В каждой строке записывается одно или несколько действий. Между действиями в строке, если их несколько, ставится точка с запятой или запятая. Запятая ставится, если первое действие должно закончиться раньше, чем начнётся второе. Точка с запятой означает, что порядок действий не имеет значения. То есть их можно выполнять как бы параллельно, для эффективности.
Пример:
Оператор безусловного перехода - это просто метка в строке. Никакого "goto" не нужно. Тоже необычно. Причём это может быть не просто метка, а произвольное арифметическое выражение, в качестве результата выдающее число, служащее меткой. Пример действия, помеченного меткой, и безусловного перехода на эту метку:
Вторая форма: обмен значениями, когда два выражения разделяются знаком "<=>". Значения по левому и правому адресам меняются местами.
В адресном языке вводится операция выделения содержимого адреса. Операция обозначается символом кавычки, который ставится слева от адреса-операнда. Называется штрих-операция первого ранга. В современном языке Си такая операция называется разыменованием и обозначается звёздочкой.
Это как "exit(0)" в Си.
Оператор цикла имеет вид:
Пример: Пусть требуется для ряда значений переменной x, размещённых по адресам α+1, α+2, ..., α+n, вычислить значение некоторой функции f(x) и поместить в адреса β+1, β+2, ..., β+n. Адресная программа такого алгоритма может быть записана в виде:
вышеприведённый текст. Компилятор выдаст следующие ошибки:
Так называемый Адресный язык был придуман программистами для математиков. Или наоборот, математиками для программистов. Дело происходило в конце 50-х в Лаборатории вычислений киевского института Математики.Та самая лаборатория и та самая команда, где создавался первая советская ЭВМ МЭСМ.
МЭСМ заработала в 1951-м и продолжала активно эксплуатироваться до 1957 года. К ней мгновенно образовалась очередь математиков, желающих чего-нибудь посчитать. Известные люди, доктора и академики, у каждого своя важная народно-хозяйственная задача. И конечно, никто не смыслит в машинных кодах, и знать не желает систему команд ЭВМ. Тем более, что она секретная и нигде не описанная.
Сложилась практика, что математики присылают свои задачи программистам на своём математическом языке. То есть набор математических формул со словесными комментариями. Задачей сотрудников Лаборатории вычислений было переложить задачу на язык машины, выполнить на ЭВМ и сообщить численные результаты. Отладка программы и верификация результатов сильно затруднялась по той простой причине, что математики не имели возможности отследить правильность машинного кода. Нужна была некая промежуточная форма, понятная и математикам-постановщика задачи, и программистам-вычислителям. Так возник Адресный язык.
Поначалу ни о какой автоматической трансляции Адресного языка в машинный код речь не шла. ЭВМ была слишком слаба для такой задачи. Машинный код порождался человеком вручную, глядя в исходник на Адресном языке, и выписывая оператор за оператором. И тем не менее, это было эффективнее, чем делать это непосредственно из исходных математических формул. Только через несколько лет, в середине 60-х была поставлена задача построения транслятора Адресного языка, и частично решена для некоторых советских ЭВМ. Но к тому времени появились Алгол и Фортран, и интерес сместился. Пошла совсем другая история.
Посмотрим, как выглядел Адресный язык. Я буду стараться использовать термины из оригинального описания языка, и показывать аналогию с современностью (в основном Си).
Программа представляет собой последовательность строк. В каждой строке записывается одно или несколько действий. Между действиями в строке, если их несколько, ставится точка с запятой или запятая. Запятая ставится, если первое действие должно закончиться раньше, чем начнётся второе. Точка с запятой означает, что порядок действий не имеет значения. То есть их можно выполнять как бы параллельно, для эффективности.
Пример:
действие
действие, действие -- последовательное выполнение
действие; действие -- параллельное выполнение
Строки могут помечаться метками. Метка ставится слева и отделяется троеточием. Меткой может быть не только имя или число, но и произвольный набор символов (что нынче смотрится несколько странно).Оператор безусловного перехода - это просто метка в строке. Никакого "goto" не нужно. Тоже необычно. Причём это может быть не просто метка, а произвольное арифметическое выражение, в качестве результата выдающее число, служащее меткой. Пример действия, помеченного меткой, и безусловного перехода на эту метку:
Оператор присваивания состоит из двух выражений, разделенных знаком "=>". Вычисляется значение первого выражения, после чего засылается в память по адресу, полученному от второго выражения. В современных языках наоборот, присваивание работает справа налево.метка... действие
метка -- безусловный переход на метку
Вторая форма: обмен значениями, когда два выражения разделяются знаком "<=>". Значения по левому и правому адресам меняются местами.
выражение => выражение -- присваивание
выражение <=> выражение -- обмен значениями
Арифметические выражения не отличаются от современных. Они состоят из операндов, знаков операций и скобок. Допускаются встроенные функции: синус, косинус и прочие.В адресном языке вводится операция выделения содержимого адреса. Операция обозначается символом кавычки, который ставится слева от адреса-операнда. Называется штрих-операция первого ранга. В современном языке Си такая операция называется разыменованием и обозначается звёздочкой.
'адрес -- чтение значения по адресу, как *ptr в Си
Две кавычки, или штрих-операция второго ранга, означает двойное разыменование. Cначала читаем значение по адресу, интерпретируем его как другой адрес, и потом по нему снова читаем значение. Штрих-операцию второго ранга можно также обозначать верхним индексом ² вместо двух кавычек. Аналогично третий ранг - индексом ³ и так далее.
''адрес -- чтение значения по адресу, прочитанному по адресу, как **ptr
²адрес -- то же самое, **ptr
³адрес -- аналогично трижды, ***ptr
Окончание выполнения программы обозначается восклицательным знаком.Это как "exit(0)" в Си.
!
Возврат из текущей подпрограммы в вызвавшую её программу обозначается перевёрнутой буквой "𐐒". Ровно как "return;" в Си.
𐐒
Вызов подпрограммы производится оператором П с параметрами.
П{a, b, c} имя -- в Си это равносильно имя(a, b, c)
Имя подпрограммы должно быть объявлено где-то в качестве метки. За ним обычно следует несколько строк, сохраняющих значения полученных параметров, в виде присваиваний с левой частью в форме символа ∅. Затем тело подпрограммы, завершающееся оператором возврата 𐐒: Например, подпрограмма с двумя параметрами a и b, возводящая a в квадрат и записывающая его в b:Условный оператор имеет вид:pow2... ∅ => a
∅ => b
'a * 'a => 'b
𐐒
P{выражение} действие1 ↓ действие2 -- предикатная формула (если-то-иначе)
Это в точности соответствует в Си оператору "if (выражение) { действие1 } else { действие2 }". Причём действие1 и действие2 здесь могут состоять из нескольких операторов Адресного языка, разделённых запятыми и/или точками с запятой. Часть P{выражение} называется предикатной функцией. Её условное выражение вычисляет "истина" или "ложь", по которым принимается решение о выполнении действия1 или действия2.Оператор цикла имеет вид:
Ц{a (b) c => x} метка
Последний оператор тела цикла помечается меткой, как в Фортране. Если тело цикла состоит только из одной строки (следующей), метку можно не ставить. В языке Си это соответствует конструкции:
for (x = a; x <= c; x += b) {
...
метка: }
Есть также форма цикла с условием вместо заданного последнего значения:
Ц{a (b) P{z} => x} метка
В языке Си это эквивалентно:
for (x = a; z; x += b) {
...
метка: }
Последняя конструкция, совершенно неожиданная в древнем языке - фактически аналог templates из нынешнего Си++. Называется формула замены:
З{a->b, c->d, e->f} начало, конец
Это означает, что берётся фрагмент кода, описанный где-то в программе, заключённый между метками "начало" и "конец", и подставляется в текущее место программы. В этом фрагменте символы a заменяются на b, символы c на d и символы e на f. Причём символы это не обязательно имена переменных: могут быть значки арифметических операций, к примеру. То, что мы сейчас называем шаблонами.Пример: Пусть требуется для ряда значений переменной x, размещённых по адресам α+1, α+2, ..., α+n, вычислить значение некоторой функции f(x) и поместить в адреса β+1, β+2, ..., β+n. Адресная программа такого алгоритма может быть записана в виде:
1 => i
k... P{'i ≤ n} ↓ !
f('(α + i)) => β + 'i
'i + 1 => i
k
Заметим, что язык недоопределён. Предположим, у нас есть компилятор с адресного языка, и мы подаём ему на входвышеприведённый текст. Компилятор выдаст следующие ошибки:
i: значение не определеноДоопределим программу, введя новый синтаксис для привязки имен к адресам или встроенным функциям. Имя, за ним двоеточие и число - задаёт численное значение для имени. Это может быть адрес в памяти или вещественная константа. Например:
n: значение не определено
α: значение не определено
β: значение не определено
f: функция не определена
i: 1
Аналогично дадим возможность давать имена встроенным функциям, например:
f: sin
Получаем законченную программу, которую можно было бы попытаться обработать (несуществующим) компилятором:
i: 1
n: 5
α: 10
β: 20
f: sin
1 => i
k... P{'i ≤ n} ↓ !
f('(α + i)) => β + 'i
'i + 1 => i
k