Синтаксис: формат, комментарии, структура программы

Свободный формат, комментарии, продолжение строк и структура программной единицы — грамматика, на которой написан весь современный Fortran.

Свободный формат (free form) — режим записи кода Fortran, где операторы располагаются в строке без привязки к номерам колонок; принят начиная с Fortran 90 и используется во всех новых программах.

Прежде чем писать содержательные программы, нужно освоить «правила правописания» языка: как разбивать строки, где ставить комментарии, чем разделять операторы и из каких частей состоит программная единица. В Fortran эти правила несут на себе отпечаток истории, и понимание этого отпечатка избавит вас от загадочных ошибок при чтении старого кода. Этот урок — про синтаксический скелет, на который мы будем наращивать мясо в следующих разделах.

Два формата: фиксированный и свободный

Исторически Fortran писали в фиксированном формате (fixed form), унаследованном от перфокарт. Каждая строка делилась на жёсткие зоны: колонки 1–5 — метки, колонка 6 — признак продолжения, колонки 7–72 — собственно код, остальное игнорировалось. Буква C или звёздочка в первой колонке означала комментарий. Этот формат всё ещё встречается в файлах .f и .for, и его надо узнавать в лицо.

Современный код пишут в свободном формате, который активируется расширением файла .f90 (и новее). Здесь нет магических колонок: оператор начинается где угодно, отступы — на ваше усмотрение, строка может быть длиной до 132 символов. Весь наш курс — свободный формат. Сравните одну и ту же мысль в двух стилях, чтобы прочувствовать разницу.

! Свободный формат (.f90) — современный
program area
  implicit none
  real :: r, s
  r = 2.0
  s = 3.14159 * r**2
  print *, "Площадь круга:", s
end program area

Здесь восклицательный знак ! открывает комментарий, который тянется до конца строки, — это универсальный синтаксис комментариев в свободном формате, работающий в любом месте строки, а не только в начале.

Структура программной единицы

Любая исполняемая программа на Fortran состоит из главной программной единицы (program) и, возможно, дополнительных единиц — процедур и модулей, которые мы изучим позже. Главная единица имеет строго заданный каркас, и порядок частей в нём важен.

program demo            ! 1. заголовок: program + имя
  implicit none         ! 2. начало раздела описаний
  integer :: n          !    объявления переменных и констант
  real    :: x

  n = 5                 ! 3. исполняемый раздел: операторы
  x = real(n) / 2.0
  print *, x
end program demo        ! 4. конец единицы

Раздел делится на две части. Сначала идёт раздел описаний: implicit none, объявления переменных, констант, типов. Затем — исполняемый раздел с операторами, которые выполняются по порядку. Смешивать их нельзя: нельзя объявить переменную после первого присваивания. Это отличает Fortran от языков, где объявления разрешены где угодно. Имя в end program demo необязательно, но указывать его — хороший тон: компилятор проверит, что вы закрываете именно ту единицу.

Продолжение длинных строк: символ &

Рано или поздно оператор перестаёт помещаться в одну строку. В свободном формате перенос делается амперсандом & в конце строки: он сообщает компилятору, что оператор продолжается на следующей. Это одна из частых причин ошибок у новичков, поэтому разберём внимательно.

program continuation
  implicit none
  real :: total
  total = 1.0 + 2.0 + 3.0 + &
          4.0 + 5.0 + 6.0
  print *, "Сумма:", total
end program continuation

Вывод:

Сумма:   21.0000000

Амперсанд в конце первой строки «склеивает» её со второй. Если внутри переноса разрывается строковый литерал или имя, амперсанд ставят с обеих сторон разрыва — и в конце первой строки, и в начале продолжения. Но в обычных арифметических выражениях достаточно одного & в конце. Запомните: амперсанд должен быть последним непробельным символом строки; если после него идёт что-то, кроме комментария, это ошибка.

Несколько операторов в строке и регистр

Иногда хочется записать несколько коротких операторов на одной строке. Разделитель — точка с запятой ;. Злоупотреблять этим не стоит, но для пары связанных присваиваний это уместно.

program multi
  implicit none
  integer :: a, b, t
  a = 3; b = 7
  t = a; a = b; b = t     ! обмен значениями через временную
  print *, a, b
end program multi

Вывод:

           7           3

Отдельно подчеркнём то, что шокирует пришедших из C: Fortran не различает регистр букв в именах и ключевых словах. Program, PROGRAM и program эквивалентны; переменные Temperature и temperature — одна и та же. Это значит, что вы не можете завести две переменные, отличающиеся только регистром. Распространённое соглашение — писать ключевые слова строчными, а длинные имена в стиле snake_case или с заглавными буквами для читаемости, помня, что для компилятора это лишь оформление.

Свободная форма и человеческая читаемость

Свободный формат — это не только освобождение от колонок, но и приглашение к аккуратному оформлению. В фиксированном формате отступы были запрещены (код жил строго с 7-й колонки), и старые программы выглядели плоской «лестницей» без структуры. Свободная форма позволяет выделять вложенность отступами, как принято в современных языках, и опытные инженеры этим пользуются: тело цикла или ветки if сдвигают вправо, чтобы структура читалась с одного взгляда. Компилятор отступы игнорирует — они существуют исключительно для человека, — но именно человек тратит на чтение кода в разы больше времени, чем на написание. В научных группах, где код переживает многих авторов и десятки лет, читаемое оформление — не косметика, а вопрос выживаемости проекта.

Ещё одна практическая деталь свободной формы — длина строки. Стандарт допускает строки до 132 символов, но многие команды по соглашению ограничиваются 80, чтобы код помещался в окне терминала и в side-by-side diff при code review. Когда выражение упирается в этот предел, на сцену выходит уже знакомый нам амперсанд продолжения. Привычка переносить длинные формулы по & с осмысленными точками разрыва (например, перед знаком + или *) делает многострочную математику читаемой, тогда как механический перенос «по достижении края» превращает формулу в кашу. Это тот случай, когда мелкая дисциплина оформления заметно влияет на надёжность.

Чувствительность к регистру в широком контексте

Нечувствительность к регистру — историческое решение, и у него есть оборотная сторона, важная при связывании с другими языками. Внутри Fortran MaxValue и maxvalue — одно имя, но когда такая процедура попадает в объектный файл, компилятор фиксирует её имя в каком-то конкретном регистре (обычно нижнем) и, возможно, добавляет подчёркивания. Код на C, чувствительный к регистру, должен обращаться к ней по этому точному имени. Именно поэтому в межъязыковом интерфейсе используют явное указание имени через bind(c, name=...), о котором речь в четвёртом уроке, — оно убирает всякую двусмысленность. Внутри же чисто фортрановского проекта о регистре можно почти не думать, но стоит выбрать единый стиль и держаться его: разнобой вроде Mass в одном месте и mass в другом сбивает читателя, хотя компилятору безразличен.

Как работает под капотом

Почему вообще существует это деление на форматы и зачем амперсанд? Ответ — в истории физического носителя. Перфокарта вмещала ровно 80 колонок; колонки 73–80 отводились под порядковый номер карты, чтобы рассыпавшуюся колоду можно было собрать обратно. Отсюда и предел в 72 колонки для кода, и колонка продолжения. Свободный формат избавил язык от этих ограничений, но компилятор по-прежнему должен отличать конец оператора от его продолжения — в C для этого служит точка с запятой в конце каждого оператора, а Fortran выбрал противоположную логику: оператор по умолчанию заканчивается концом строки, а чтобы продолжить — нужен явный знак &.

Лексический анализатор компилятора, встретив & на конце строки, не завершает текущий оператор, а «дочитывает» следующую строку, склеивая токены. Комментарий ! вырезается ещё раньше, на стадии предобработки строки, поэтому он может стоять и после кода, и после амперсанда — но не между амперсандом и концом строки в роли «продолжения».

Любопытно сравнить философию завершения операторов в разных языках. C, Java, JavaScript требуют точку с запятой в конце каждого оператора — конец строки для них незначим. Python, наоборот, придаёт концу строки смысл и продолжает строку либо неявно (внутри скобок), либо через обратную косую черту. Fortran ближе к Python: конец строки завершает оператор, а явный знак нужен для продолжения. Каждый подход — компромисс между «шумом» лишних символов и риском незаметной ошибки переноса. Зная, к какому лагерю принадлежит язык, вы избегаете машинального переноса строк из чужих привычек.

Частые ошибки

  • Объявление переменной в исполняемом разделе. Все integer ::, real :: и прочие описания обязаны идти до первого исполняемого оператора. Компилятор выдаст ошибку, если нарушить порядок.
  • Забытый амперсанд при переносе. Если длинное выражение просто перенести на новую строку без &, компилятор сочтёт это двумя отдельными (и неверными) операторами.
  • Символ продолжения не последний. Любой непробельный символ после & (кроме начала комментария) ломает перенос.
  • Смешение форматов. Попытка скомпилировать код в стиле перфокарт как .f90 приводит к загадочным ошибкам — следите за расширением файла и стилем.
  • Расчёт на регистр. Две «разные» переменные x и X — это одна переменная; такой код ведёт себя не так, как ожидает программист из C.

Итоги

  • Современный Fortran пишут в свободном формате (файлы .f90); фиксированный формат — наследие перфокарт.
  • Комментарий открывается ! и тянется до конца строки в любом месте.
  • Программная единица состоит из заголовка, раздела описаний и исполняемого раздела — именно в этом порядке.
  • Длинные строки переносят амперсандом & в конце; он должен быть последним непробельным символом.
  • Несколько операторов в строке разделяют точкой с запятой ;.
  • Имена и ключевые слова нечувствительны к регистру — закладывайте это в свои соглашения об именовании.
Проверьте себя
1. Каким символом в свободном формате открывается комментарий?
A// (две косые черты)
B# (решётка)
C! (восклицательный знак)
DC в первой колонке
2. Как перенести длинный оператор на следующую строку в свободном формате?
AПоставить \ в конце строки
BПоставить & в конце строки
CПросто перенести без символа
DПоставить ; в конце строки
3. Что верно про регистр символов в именах Fortran?
AMass и mass — разные переменные
BИмена чувствительны к регистру, как в C
CMass, mass и MASS — одна и та же переменная
DРегистр влияет только на ключевые слова