Pull to refresh

К 70-летию Фортрана. Историческая справка. Часть I

Level of difficultyEasy
Reading time13 min
Views7.1K

Когда умрёт последний программист на $(вашем любимом языке), его тело отвезут на кладбище на катафалке, конструкция которого будет рассчитана на Фортране, а счёт на организацию похорон сформирует программа, написанная на Коболе (Старинная американская мудрость).

В 2023 году исполняется 70 лет с того момента, как Джон Бэкус, сотрудник IBM, убедил начальство утвердить проект первого в мире языка программирования высокого уровня. Как настоящий уважающий себя программист того времени, Бэкус занимался расчётом траекторий баллистических ракет, и его очень раздражало писать такие вещи на ассемблере, а тем более – руководить разработкой таких вещей на ассемблере. В итоге команда из 10 программистов под руководством Бэкуса разработала язык Фортран и первый компилятор для машины IBM 704, представив первые результаты в 1954 году и затратив на разработку 18 человеко-лет. Попутно для формализованного описания синтаксиса Фортрана была разработка ставшая классической форма Бэкуса-Наура (БНФ).

Условно эволюцию языка Фортран можно разделить на классический период (Фортран I – Фортран IV), когда ведущую роль в разработке занимала фирма IBM, язык абсолютно доминировал среди программистов (особенно в США) и сохранял значительную преемственность с самой первой версией; и современный период (Фортран 90 – Фортран 2018), когда разработка велась в основном ISO, синтаксис и семантика языка были значительно осовременены, но, несмотря на это, язык был уже вытеснен на периферию инструментальных средств. Версия Фортран 77, не получившая широкого распространения вследствие доминирования Фортрана IV, занимает промежуточное положение между этими периодами.

Фортран I

Первая версия языка Фортран (которую условно можно было бы назвать Фортран I или Фортран 54) не слишком сильно отличалась от макроассемблера. Основным отличием была возможность записывать арифметические выражения так, как это сейчас общепринято в программировании, то есть похоже на математические формулы (собственно, название Фортран расшифровывается как Формульный транслятор).

Программа на Фортране I записывалась в виде одного монолитного модуля. Всего было реализовано 32 оператора, среди них такие управляющие конструкции, как оператор переходаGOTO (безусловный переход на метку или переход на метку, записанную в значение переменной), оператор цикла с параметром DO и условный оператор IF.

Как указал @victor_1212 в комментарии к этой статье, в первоначальной спецификации языка цикл DO мог содержать три метки – метку первого оператора тела цикла, метку последнего оператора тела цикла и метку оператора, который выполнялся после выхода из цикла. Таким образом, тело цикла могло быть текстуально не связанным с его заголовком. Например: DO 10,14,50 I=4,20,2 , что означало: выполнять операторы с метки 10 по метку 14 для значений I от 4 до 20 с шагом 2, после окончания цикла перейти на метку 50. Также допускалась и более простая форма, например, в простейшем случае: DO 14 I=4,20 , что означало: выполнять операторы после DO до метки 14 для значений I от 4 до 20 с подразумеваемым шагом 1, затем продолжить выполнение после метки 14.

Оператор IF записывался в виде IF (V1 op V2) L1,L2 , где V1 и V2 – константы, простые переменные или целочисленные выражения вида a*b+c (очевидно, они вычислялись одной машинной командой в индексных регистрах), op – одна из операций =, > или >=, а L1 и L2 – метки, на которые выполнялся переход в случае истинности или ложности условия. Например: IF (N*I >= K+1) 3,9. Не совсем понятно, как вводился в машину знак > на оборудовании IBM 704. Возможно, операции в таком виде записывались только в рукописном тексте, а на реальном оборудовании кодировались буквенно-точечными обозначениями, как в Фортране IV.

Также в Фортране I были специальные формы оператора IF для проверки различных флажков процессора IBM 704.

Фортран I сразу же включал различные формы операторов форматного и бесформатного ввода-вывода, в том числе специальные операторы для управления магнитной лентой и магнитным барабаном.

Всё распределение памяти в классическом Фортране было статическим. Допускались простые целочисленные и вещественные переменные и массивы.

В ранних версиях Фортрана тип переменной определялся строго по её имени. Если имя начиналось с букв I,J,K,L,M,N, то переменная была целой, иначе – вещественной. При этом в целочисленных и вещественных переменных также можно было содержать значения меток (т.е. адресов) и строк символов фиксированной длины, совпадающих с базовым типом по объёму памяти. Массивы в Фортране I могли иметь до 3 измерений, а их размерность задавалась отдельным оператором DIMENSION (потерявшим популярность, но дошедшим до наших дней), не связанным с определением типа.

Очень долгое время, весь классический период, строки символов находились в Фортране на таком положении бедного родственника, не имея даже собственного типа переменных, не говоря о произвольной длине. Строковые значения записывались в виде так называемых “холлеритовых констант”, имевших вид длинаHсимволы, например, 5HALPHA. Интересной особенностью Фортрана является то, что холлеритовы (и позднее шестнадцатиричные) константы считаются не имеющими типа. Это просто заполненные области памяти машины, которые принимают тип по способу своего использования. Поскольку классический Фортран разрабатывался в то время, когда байтовая организация памяти сначала не была изобретена, а потом не имела повсеместного использования, то холлеритовы константы не имели определённого языком размера в памяти, их длина в словах зависела от реализации. Например, константа 5HALPHA могла занимать 30 бит в 6-битовой кодировке в одном 48-битовом слове на одной машине (и тогда могла храниться в одной целой или вещественной переменной), либо 40 бит в 8-битной кодировке в двух 32-битовых словах на другой машине (и тогда могла храниться в массиве из двух целых или вещественных элементов или в вещественной переменной двойной точности).

Таким образом, ранний Фортран формально был языком со статической явной типизацией, в котором отсутствовали описания типов и имелись бестиповые значения.

Так как всё управление ходом вычислений в раннем Фортране было основано на метках и их использовании в различных операторах, то текст программы, как правило, представлял собой классические логические спагетти. От этого недостатка удалось уйти только к концу 20 века. Очень интересной особенностью Фортрана I был операторFREQUENCY. Он представлял собой подсказку для компилятора к арифметическому IF, и в этом операторе программист задавал априорные вероятности перехода по каждому из возможных путей. Используя эти вероятности, компилятор при трансляции программы выполнял симуляцию методом Монте-Карло (!) и по её результатам принимал решение о наиболее эффективном размещении блоков кода в памяти машины, чтобы уменьшить число переходов.

Операторы Фортрана I размещались в фиксированных позициях перфокарт. Первые 5 позиций были отведены под метку или признак комментария, 6-я позиция – под признак продолжения, позиции с 7 по 72 – под текст оператора, с 73 по 80 – под произвольный текст (обычно там записывался номер перфокарты, чтобы можно было собрать рассыпавшуюся колоду). Такой фиксированный формат сохранялся до конца 20 века, хотя перфокарты перестали использоваться гораздо раньше, а неспособностью воспринимать текст дальше 72 позиции отличался только перфокарточный ввод собственно IBM 704. Пробелы в операторах игнорировались.

В своей статье об успехах разработки первого компилятора Фортрана Бэкус с соавторами утверждал, что после однодневного обучения языку новый программист оказывался в состоянии самостоятельно писать на нём программы, и, например, мог написать программу из 47 операторов Фортрана, которая компилировалась на IBM 704 шесть минут, превращалась примерно в 1000 машинных инструкций, и со второго раза при этом удавалось устранить ошибки и получить работающий код, который на ассемблере пришлось бы писать вручную три дня и неизвестно сколько отлаживать. В общем, высокоуровневое программирование показало свою перспективность. Делались даже такие утверждения, что использование Фортрана устраняет необходимость отладки, так как в программах и так сразу всё ясно.

Отметим, что выпущенная в IBM спецификация языка Фортран I, ссылка на которую приведена выше, занимала 29 машинописных страниц, то есть примерно 15 печатных.

Фортран II

В 1958 году в IBM был реализован язык Фортран II, основным отличием которого от Фортрана I была реализация многомодульных программ в виде раздельно транслируемых главной программы, подпрограмм (процедур) и функций, между которыми могли передаваться параметры и общий блок памяти. Модули программы объединялись только на этапе компоновки, и никакого контроля за совпадением описаний параметров и общего блока в классическом Фортране не было. Если, например, подпрограмма или функция имела формальные параметры с одними типами и количеством, а вызывалась с другими, то получалось нехорошо. Так как к тому же все параметры в классическом Фортране передавались по ссылке, в том числе и константы, то таким образом можно было ненамеренно достигать очень интересных результатов, например, присваивать литеральным константам новые значения, передавая их вместо переменных (допустим, присвоить литералу 2 значение 1).

В цикле DOбыла оставлена одна форма с меткой конца цикла. Арифметический IF теперь выполнял переход на одну из трёх меток в зависимости от знака указанного в нём арифметического выражения – отрицательное, ноль или положительное.

Также в Фортран II были добавлены описания простых типов, в том числе новых типов COMPLEX и DOUBLE PRECISION. Но основным механизмом описания переменных в классическом Фортране всё равно оставалось описание по умолчанию, в зависимости от первой буквы имени.

Википедия приводит следующий пример программы на Фортране II:

C AREA OF A TRIANGLE WITH A STANDARD SQUARE ROOT FUNCTION
C INPUT - TAPE READER UNIT 5, INTEGER INPUT
C OUTPUT - LINE PRINTER UNIT 6, REAL OUTPUT
C INPUT ERROR DISPLAY ERROR OUTPUT CODE 1 IN JOB CONTROL LISTING
      READ INPUT TAPE 5, 501, IA, IB, IC
  501 FORMAT (3I5)
C IA, IB, AND IC MAY NOT BE NEGATIVE OR ZERO
C FURTHERMORE, THE SUM OF TWO SIDES OF A TRIANGLE
C MUST BE GREATER THAN THE THIRD SIDE, SO WE CHECK FOR THAT, TOO
      IF (IA) 777, 777, 701
  701 IF (IB) 777, 777, 702
  702 IF (IC) 777, 777, 703
  703 IF (IA+IB-IC) 777, 777, 704
  704 IF (IA+IC-IB) 777, 777, 705
  705 IF (IB+IC-IA) 777, 777, 799
  777 STOP 1
C USING HERON'S FORMULA WE CALCULATE THE
C AREA OF THE TRIANGLE
  799 S = FLOATF (IA + IB + IC) / 2.0
      AREA = SQRTF( S * (S - FLOATF(IA)) * (S - FLOATF(IB)) *
     +     (S - FLOATF(IC)))
      WRITE OUTPUT TAPE 6, 601, IA, IB, IC, AREA
  601 FORMAT (4H A= ,I5,5H  B= ,I5,5H  C= ,I5,8H  AREA= ,F10.2,
     +        13H SQUARE UNITS)
      STOP
      END

Язык Фортран к тому времени пошёл на ура (хотя Дейкстра, разумеется, критиковал его, как и вообще всё, в чём он или его друзья не имели личного интереса) и заинтересовал других производителей компьютеров, помимо IBM. Стали появляться первые альтернативные реализации.

Довольно известный старый тест производительности Whetstone написан на языке Фортран II.

Фортран III

Версия языка Фортран III была внутренним продуктом IBM, который позволял использовать в программах ассемблерные вставки для IBM 704 (естественно, это не понадобилось впоследствии) и использовать логические выражения и формат типа "А" для ввода-вывода строковых данных (а это понадобилось впоследствии). Компилятор Фортрана III использовался примерно в 20 экземплярах и не дошёл до стадии коммерческого релиза.

Фортран IV

Версия Фортран IV была реализована в IBM в 1962 году и с небольшими изменениями стандартизована ANSI в 1966. Впоследствии этот стандарт получил неофициальное название Фортран 66. Отчасти благодаря своим востребованным функциям, отчасти благодаря реализации имевшей огромное влияние серии машин IBM S/360 в 1964 году, Фортран IV получил ошеломительный успех и стал доминирующим языком программирования на следующую четверть века, вплоть до кризиса мейнфреймов. На Фортране IV были написаны все основные библиотеки физических и инженерных расчётов, многие из которых используются до сих пор. Если рассматривать причины использования Фортрана в настоящее время, то основной из них является совместимость с кодом, разработанным на Фортране IV.

Фортран IV унаследовал от Фортрана III логические выражения и позволил писать что-то хотя бы отчасти напоминающее современные условные операторы – логический IF с одним оператором в его теле, которым чаще всего по понятным причинам оказывался GOTO.

С логическими выражениями всё было не совсем прекрасно, потому что на клавиатурах того времени зачастую не было символов сравнения, и в Фортране IV было принято решение заменять их буквенными обозначениями в точках, такими как .GT. вместо “больше”, .LT. вместо “меньше”, .NE. вместо “не равно” и т.д.

Появились более чем трёхмерные массивы, указание размеров переменных в байтах и много других небольших, но существенных улучшений.

Точная семантика цикла DO в классических версиях Фортрана зависела от реализации. Например, в реализациях IBM цикл всегда выполнялся минимум один раз, так как проверка выхода управляющей переменной из диапазона выполнялась как постусловие, а в реализациях CDC – мог не выполниться ни разу, так как проверка выполнялась как предусловие.

Пример программы на Фортране IV:

      INTEGER*4 NOBJ, NUMTRA, NIS
      REAL*8    DT
      INTEGER*4 NP
      REAL*8    TOBJTR, OBJTR1, OBJTR2
      NOBJ = 2
      WRITE (1) NOBJ
      DO 2 I = 1, NOBJ
      NUMTRA = I * 2
      NIS = I * 2 + 10
      WRITE (1) NUMTRA, NIS
      DT = 1E-4
      NP = 2
      WRITE (1) DT, NP
      K = NUMTRA / 2
      DO 1 J = 1, K
      TOBJTR = 100. + J
      OBJTR1 = .11
      OBJTR2 = .12
      WRITE (1) TOBJTR, OBJTR1
      IF (J.NE.K) WRITE (1) TOBJTR, OBJTR2
1     CONTINUE 
2     CONTINUE 
      STOP
      END

Отметим здесь две вещи. Во-первых, пустые операторы CONTINUE, на которые постепенно стало модно ставить метки. Во-вторых, оператор останова STOP, которым принято было заканчивать программу, хотя фактически он, находясь в конце программы, ничего не делал, а в середину его было ставить уже как-то некрасиво. Именно в таких странных формах идеи структурного программирования понемногу овладевали массами.

Вместе с Фортраном развивались теория и практика компиляции, что позволило создавать очень сложные оптимизирующие компиляторы. Например, уже для IBM 1401 был реализован 63-проходный компилятор.

Вершиной изысканий IBM являлся оптимизирующий компилятор FORTRAN IV уровня H для OS/360 и совместимых систем. Компилятор FORTRAN IV (H) был настолько хорош, что в дальнейшем программисты систем IBM практически проигнорировали появление компилятора Фортрана 77 со значительно более удобным языком, так как код, порождаемый старым компилятором, был эффективнее. Аналогичная ситуация складывалась и у других производителей.

Наиболее вычислительно производительные компьютеры в то время выпускала компания CDC (их главный конструктор, Сеймур Крей, впоследствии организовал собственную фирму). Для компьютеров CDC был разработан очень мощный компилятор Фортрана 66, получивший огромную популярность среди физиков во всём мире (этот компилятор в CDC пытались назвать FORTRAN V, чтобы выглядеть превзошедшими IBM на поколение, но название не прижилось). Для советской машины БЭСМ-6, на архитектуру которой в целом оказала значительное влияние CDC, был реализован компилятор, полностью совместимый с CDC FORTRAN.

В целом, любая машина того периода, претендующая на проведение расчётов, должна была иметь хороший компилятор Фортрана IV. И даже многие не претендующие на такое машины, например, 8-разрядный домашний компьютер Apple II, имели компиляторы Фортрана.

Очевидным производным от Фортрана IV является классический Бейсик семидесятых-восьмидесятых годов (с номерами строк).

Фортран IV имел развитую систему ввода-вывода, но характерную для своего времени проблему: внешнюю привязку файлов. Поскольку в то время файловые системы в современном виде ещё не были изобретены, то программы на Фортране IV работали с файлами просто по номерам. Вопрос о том, как из этого номера получается реальное имя (если оно есть) и размещение файла, никак не регулировался языком. На практике, операционные системы шестидесятых годов обеспечивали привязку специальными операторами языка управления заданиями, которые исполнялись операционной системой до запуска фортрановской программы. Этими операторами задавалось, например, что фортрановский файл номер 6 привязан к системному принтеру, а файл номер 1 привязан к определённой области на диске. Некоторые поздние реализации обеспечивали привязку файлов путём нестандартного для того времени оператора OPEN.

Фортран 77

К 70-м годам фирма IBM несколько охладела к Фортрану, который пыталась заменить разработанным ей более совершенным языком PL/I, включающим все возможности Фортрана, Кобола, Алгола и многое сверх того. Некоторые программисты действительно перешли на PL/I, но многие, особенно среди учёных, не занимающихся программированием профессионально, продолжали программировать на Фортране IV. У них было три аргумента против PL/I: Фортран IV – простой для изучения язык, на Фортране IV написано много кода и Фортран IV имеет более эффективный компилятор.

На фоне этой возни, созданный в ANSI комитет X3J3, с 1966 года занимавшийся Фортраном, разработал новый стандарт Фортран 77. Это был более продвинутый язык, чем Фортран 66, который стандартизовал многие расширения IBM, имевшиеся в Фортране IV, но не вошедшие в стандарт Фортран 66, а сверх того Фортран 77 включал: символьный тип, блочный оператор IF, операторы OPEN и CLOSE, оператор PARAMETER для констант и ещё разное по мелочи. Также стандартом Фортран 77 впервые были запрещены выход за границу массива и переход оператором GOTO внутрь цикла (из чего можно сделать вывод, какие не омрачённые условностями нравы царили в программировании до того).

Впервые была зафиксирована точная семантика цикла DO. Эта семантика в своих деталях довольно любопытна и отличается от всех остальных практически используемых языков программирования. Перед выполнением цикла вычисляются значения нижней границы, верхней границы и шага цикла, и на их основании рассчитывается целочисленное значение счётчика выполнений. Независимо от этого, управляющей переменной присваивается значение нижней границы. В прологе цикла проверяется не нулевой ли счётчик, и если нулевой – цикл заканчивается. В эпилоге цикла счётчик декрементируется, а к управляющей переменной прибавляется шаг, зафиксированный в самом начале, и производится переход в начало цикла. (Из этого следует, между прочим, что в каких-то случаях значение вещественной переменной цикла может вовсе не изменяться из-за незначимости шага, а цикл – такой как DO 1 X = 1E7, 1E8, 0.1 – тем не менее, завершится).

IBM и другие фирмы реализовали компиляторы Фортрана 77 (причём в компиляторе IBM даже предусматривалась опциональная возможность уйти от синтаксиса с фиксированными позициями).

Производители в то время реализовывали многочисленные расширения Фортрана 77, некоторые из которых стали стандартом де-факто, а позже де-юре вошли в Фортран 90. Среди обычных для того времени расширений был структурный оператор DO, заканчивавшийся операторной скобкой END DO, оператор DO WHILE, операторы CYCLE и EXIT для управления выполнением цикла и операторIMPLICIT NONE для отмены неявного описания переменных по первой букве. Всё это можно было рассматривать, как начало облагораживающего влияния на Фортран языка PL/I.

В 1978 году американские военные выкатили свои требования к компиляторам Фортрана MIL-STD-1753, включающие некоторые расширения Фортрана 77. Сам по себе документ MIL-STD-1753 очень короткий и не очень последовательный. Например, он вводит оператор END DO, но разрешает использовать его без метки только в цикле DO WHILE, а в цикле DO с управляющей переменной оператор END DO может выполнять только функцию места для метки вместо CONTINUE.

Пример программы на расширенном Фортране 77:

* This program computes the prime numbers between 1 and 10000
* using the Sieve of Eratosthenes algorithm.

      IMPLICIT NONE
      INTEGER UPBOUND
      PARAMETER (UPBOUND=10000)
      INTEGER I, K, PRIMES
      LOGICAL*1 NUMBERS(2:UPBOUND)
      CHARACTER*11 FORM
      PARAMETER (FORM='(A,I5,A,I5)')
      DO I = 2, UPBOUND
          NUMBERS(I) = .TRUE.
      ENDDO
      PRIMES = 0
      DO I = 2, UPBOUND
          IF( NUMBERS( I ) )THEN
              PRIMES = PRIMES + 1
              DO K = I + I, UPBOUND, I
                  NUMBERS( K ) = .FALSE.
              ENDDO
          ENDIF
      ENDDO
      PRINT FORM, 'The Number of Primes between 1 and ', UPBOUND,
     1            ' are: ', PRIMES
      END

Из интересных расширений Фортрана 77, не вошедших в дальнейшие стандарты языка, следует упомянуть управляющий оператор GUESS, реализованный в компиляторе Watcom Fortran. Он имел следующий вид:

      GUESS [: block-label]
        statement(s)
      ADMIT
        statement(s)
      ADMIT
        statement(s)
С     . . .
      ADMIT
        statement(s)
      END GUESS

Семантика оператора следующая. Войдя в оператор GUESS, мы начинаем выполнять первую ветку. В этой ветке мы выполняем произвольные операторы с целью определить, реализуется ли какая-то первая логическая альтернатива в нашей программе. Если мы приходим к выводу, что мы не находимся в первой альтернативе, то выполняем оператор QUIT, который осуществляет переход к следующему ADMIT. Если же мы попали в нужную альтернативу, то код нашей ветки выполняется до конца, и управление переходит к END GUESS. Например:

      GUESS
        IF( CH .LT. ’a’ ) QUIT
        IF( CH .GT. ’z’ ) QUIT
        PRINT *, ’Lower case letter’
      ADMIT
        IF( CH .LT. ’A’ ) QUIT
        IF( CH .GT. ’Z’ ) QUIT
        PRINT *, ’Upper case letter’
      ADMIT
        IF( CH .LT. ’0’ ) QUIT
        IF( CH .GT. ’9’ ) QUIT
        PRINT *, ’Digit’
      ADMIT
        PRINT *, ’Special character’
      END GUESS

Однако, ни гражданский, ни военный стандарт Фортрана 77, ни их расширения не были особенно востребованы за пределами преподавания в университетах. Как можно легко догадаться, программисты на Фортране выдвигали три аргумента против Фортрана 77: Фортран IV – простой для изучения язык, на Фортране IV написано много кода и Фортран IV имеет более эффективный компилятор.

К 1990 году, когда автор впервые получил возможность зарабатывать на жизнь в том числе и Фортраном, это уже был очень архаичный язык, который, однако, имел значительную сферу применения. Стандарт Фортран 77 не получил значительного распространения, и в ходу среди реально программирующих людей был Фортран IV. Фиксированный формат записи, 6-символьные идентификаторы, только статические переменные, раздельная компиляция, отсутствие блочных операторов и лапша из меток и GOTO – всё это в любой нише программирования смотрелось довольно странно на фоне таких развитых языков того времени, как PL/I для мейнфреймов и Паскаль и Си для машин поменьше. При этом действительно существовала огромная масса унаследованного программного обеспечения, которое никому не хотелось менять. Фирма Microsoft, например, одними из первых реализовала компиляторы Фортрана для MS-DOS и позже для Windows. Со всем этим следовало что-то делать.

О современном периоде Фортрана (1991–2023) – в следующей статье.

Only registered users can participate in poll. Log in, please.
Доводилось ли вам писать программы на Фортране?
13.33% Да, за деньги26
25.13% Да, по любви49
23.59% Да, по принуждению46
24.62% Как вы могли такое обо мне подумать?48
8.21% Не помню16
5.13% Что такое Фортран?10
195 users voted. 28 users abstained.
Tags:
Hubs:
Total votes 30: ↑29 and ↓1+28
Comments34

Articles