Почему стандарт C запрещает токен частичной предварительной обработки в конце исходного файла?

Я читаю проект стандарта ISO C n3096 и обращаю внимание на следующее жирное утверждение (§ 5.1.1.2 p1):

  1. Исходный файл разбивается на токены предварительной обработки и последовательности символов пробелов (включая комментарии). Исходный файл не должен заканчиваться частичным токеном предварительной обработки или частичным комментарием. Каждый комментарий заменяется одним символом. Символы новой строки сохраняются. Сохраняется ли каждая непустая последовательность символов пробела, кроме символа новой строки, или заменяется одним символом пробела, определяется реализацией.

Это утверждение также присутствует в C90 и, предположительно, во всех промежуточных стандартах.

Мой вопрос: почему Стандарт явно запрещает исходному файлу заканчиваться токеном частичной предварительной обработки? Не становится ли это утверждение избыточным из-за других объявлений неопределенного поведения?


Во-первых, я изложу свое (неправильное) понимание.

В качестве рабочего определения, поскольку стандарт C не упоминает «токен частичной предварительной обработки» где-либо еще, я полагаюсь на эту информативную сноску в стандарте C++ (n4928, § 5.2 [lex.phases]):

10) Токен частичной предварительной обработки может возникнуть из исходного файла, заканчивающегося первой частью многосимвольного токена, который требует завершающей последовательности символов, например имени заголовка, в котором отсутствует закрывающий " или >. ...

...где имя-заголовка является своего рода определенным токеном предварительной обработки (§ 6.4 p1)

токен предварительной обработки:

  • имя заголовка
  • идентификатор
  • pp-номер
  • константа символа
  • строковый литерал
  • пунктуатор
  • каждое имя универсального символа, которое не может быть одним из вышеперечисленных
  • каждый символ без пробелов, который не может быть одним из вышеперечисленных

Исходя из этого, я считаю, что токены предварительной обработки, которые могут быть «частичными», включают, по крайней мере, имя заголовка, символьную константу, строковый литерал и шестнадцатеричную плавающую константу (разновидность pp-числа, которое заканчивается двоичной экспонентой). -часть).

Что касается заявления о запрете токенов частичной предварительной обработки в конце исходного файла: я предполагаю, что оно не является избыточным и запрещает некоторые случаи, которые еще не запрещены где-либо еще. Предполагая, что исходный файл, заканчивающийся токеном частичной предварительной обработки, не пуст, и учитывая, что непустой исходный файл уже должен заканчиваться символом новой строки, не являющимся частью сращивания строк (§ 5.1.1.2 p1), I полагают, что вышеупомянутое утверждение описывает случай, когда исходный файл заканчивается символом новой строки, не являющимся частью соединения строк, а также заканчивается токеном частичной предварительной обработки; поэтому токен частичной предварительной обработки содержит новую строку после фазы трансляции 2.

Но токены предварительной обработки не содержат новых строк после TP 2. (хотя комментарии могут, поэтому запрет частичных комментариев имеет для меня смысл.)

(Если это актуально, меня также смущает концепция частичного токена предварительной обработки... Очевидно, это не токен предварительной обработки, но я думал, что недопустимых токенов предварительной обработки нет из-за резервного варианта в предварительной обработке- правило токена: «каждый символ без пробелов, который не может быть одним из вышеперечисленных».)


Извините за длинный вопрос...

Большое спасибо,

Проверил стандарт и эмм все гораздо сложнее, чем я думал. Во время этого исследования я усвоил несколько стандартных определений. Я думаю, что оператору следовало прочитать это, но, возможно, это поможет другим людям, которые видят этот пост, как и я: Pastebin.com/gKZuKCpC

Limina102 04.08.2024 04:42

Я подозреваю, что это во многом прагматично. Попытайтесь представить, что пришлось бы делать полностью совместимому со стандартами препроцессору и токенизатору, если бы этого правила не было. Оно допускает реализацию препроцессора, о которой очень легко рассуждать. В противном случае препроцессор может вставить содержимое файла из-за #include, и внезапно все содержимое впоследствии может потребовать повторной токенизации и предварительной обработки (дважды? до/после того, как этот #include был расширен?), и вы не сможете по закону для независимой токенизации заголовочных файлов.

alter_igel 04.08.2024 04:47

@Limina102 Спасибо за быстрый ответ! Я добавил в пост пару ваших выдержек.

nore 04.08.2024 05:19
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
107
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваш вопрос кажется почти таким же, как в отчете о дефекте 324 https://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_324.htm , в котором спрашивается:

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


В качестве рабочего определения, поскольку стандарт C не упоминает «токен частичной предварительной обработки» в

Из DR324:

«Токен частичной предварительной обработки» сам по себе не является техническим термином; это просто английское слово «частичный», модифицирующее технический термин «токен предварительной обработки». Маркер предварительной обработки определяется грамматическим нетерминальным маркером предварительной обработки в подразделе 6.4. Таким образом, токен частичной предварительной обработки — это всего лишь часть токена предварительной обработки, который не является полным токеном предварительной обработки.


почему стандарт явно запрещает исходному файлу заканчиваться токеном частичной предварительной обработки? Не становится ли это утверждение избыточным из-за других объявлений неопределенного поведения?

Из DR324:

Утверждение о том, что «исходные файлы не должны заканчиваться частичным токеном предварительной обработки или частичным комментарием», имеет два значения. Во-первых, токен предварительной обработки не может начинаться в одном файле и заканчиваться в другом файле. Во-вторых, последний токен предварительной обработки в исходном файле должен быть правильно сформированным и полным. Например, последний токен не может быть строковым литералом, в котором отсутствует закрывающая кавычка.


В целом, я думаю, что проблема в следующем:

// string.h
"am I a string

// main.c
#include <string.h>\
literal?"

Мне не было известно о соответствующем отчете о дефекте, спасибо за ссылку! Намерение состоит в том, что токены предварительной обработки не могут охватывать несколько файлов из-за #include, для меня имеет большой смысл.

nore 04.08.2024 05:47

Третьим следствием этого утверждения является то, что завершение файла токеном частичной предварительной обработки является нарушением ограничения, и поэтому при его обнаружении должна быть выдана диагностика, даже если фактическое поведение не определено.

Nate Eldredge 04.08.2024 08:02

@NateEldredge Не могли бы вы объяснить, почему подразумевается ограничение?

nore 04.08.2024 08:15

@nore: Я имею в виду, что это явно ограничение, определенное в 3.8, не так ли?

Nate Eldredge 04.08.2024 08:21

@NateEldredge Я не эксперт, но считаю, что ограничения должны быть введены явно со словом «ограничение». Например: «Если они объявлены, параметры функции main должны подчиняться следующим ограничениям» (раздел 5.1.2.2.1 p2). Или ограничения можно ввести в подзаголовке «Ограничения». Рассматриваемое утверждение не имеет этого контекста, поэтому слово «не должно» вместо этого описывает UB (§ 4 p2). В Приложении J.2 мы также видим, что это заявление занимает второе место в списке UB. (Хотя Приложение J носит информативный характер.)

nore 04.08.2024 20:25

Другие вопросы по теме