Подтвердить что ты не робот

Как синтаксический анализатор для С++ проводит различие между сравнениями и экземплярами шаблонов?

В С++ символы '<' и ' > ' используются для сравнения, а также для обозначения аргумента шаблона. Таким образом, фрагмент кода

[...] Foo < Bar > [...]

может быть интерпретирован как любой из следующих двух способов:

  • Объект типа Foo с аргументом шаблона Bar
  • Сравните Foo с Bar, затем сравните результат с тем, что будет дальше.

Как синтаксический анализатор компилятора С++ эффективно решает эти две возможности?

4b9b3361

Ответ 1

Если известно, что Foo является именем шаблона (например, объявление template <...> Foo ... находится в области видимости или компилятор видит последовательность template Foo), то Foo < Bar не может быть сравнением. Это должно быть начало экземпляра шаблона (или что-то вроде Foo < Bar > на этой неделе).

Если Foo не является именем шаблона, то Foo < Bar является сравнением.

В большинстве случаев известно, что Foo, потому что идентификаторы обычно должны быть объявлены перед использованием, поэтому нет никаких проблем, чтобы решить одно или другое. Там одно исключение: разбор кода шаблона. Если Foo<Bar> находится внутри шаблона, а значение Foo зависит от параметра шаблона, то неизвестно, является ли Foo шаблоном или нет. Стандарт языка, предназначенный для обработки, является не-шаблоном, если не указано ключевое слово template.

Синтаксический анализатор может реализовать это, возвращая контекст в lexer. Lexer распознает Foo как разные типы токенов, в зависимости от контекста, предоставляемого синтаксическим анализатором.

Ответ 2

Важно помнить, что грамматика С++ не является контекстно-зависимой. I., когда анализатор видит Foo < Bar (в большинстве случаев), знает, что Foo относится к определению шаблона (путем поиска его в таблице символов) и, следовательно, < не может быть сравнением.

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

 a->template foo<int>();

(в некоторых случаях см. Вызов функции шаблона в классе шаблона для получения более подробной информации)

Кроме того, сравнения внутри аргументов шаблона не-типа должны быть окружены скобками, то есть:

foo<(A > B)>

не

foo<A > B>

Нестатические инициализаторы элементов данных приносят больше удовольствия: http://open-std.org/JTC1/SC22/WG21/docs/cwg_active.html#325

Ответ 3

C и С++ парсеры являются "контекстно-зависимыми", другими словами, для данного токена или лексемы, он не гарантированно отличается и имеет только одно значение - он зависит от контекста, в котором используется токен.

Итак, часть анализатора компилятора будет знать (понимая "где в источнике это" ), что он анализирует какой-то тип или какое-то сравнение (это НЕ ПРОСТОНО, поэтому чтение источник компетентного компилятора C или С++ не совсем прямолинейный - есть много условий и проверка функциональных вызовов. "Это один из них, если это так, иначе сделайте что-нибудь еще" ).

Ключевое слово template помогает компилятору понять, что происходит, но в большинстве случаев компилятор просто знает, потому что < не имеет смысла в другом аспекте - и если это не имеет смысла в EITHER форма, то это ошибка, поэтому просто нужно выяснить, что может потребоваться программисту - и это одна из причин, по которой иногда простая ошибка, такая как отсутствие } или template, может приводят к полному разбору анализа и приводят к сотням или тысячам ошибок [хотя программисты-программисты останавливаются после разумного числа, чтобы не заполнить весь юниор сообщениями об ошибках]

Ответ 4

Большинство ответов здесь путают определение значения символа (то, что я называю "разрешение имен" ) с синтаксическим разбором (определен узко как "может читать синтаксис программы" ).

Вы можете выполнять эти задачи отдельно..

Это означает, что вы можете создать абсолютно свободный от контекста парсер для С++ (как это делает моя компания, Semantic Designs), и оставить вопросы о том, что означает смысл символа в явно отдельной задаче.

Теперь эта задача управляется возможными синтаксическими интерпретациями исходного кода. В наших парсерах они воспринимаются как двусмысленности в анализе.

Какое разрешение имен собирает информацию об объявлениях имен и использует эту информацию, чтобы определить, какой из двусмысленных парсетов не имеет смысла, и просто отказаться от них. Остается один действительный синтаксический анализ с единственной допустимой интерпретацией.

Техника для достижения разрешения имен на практике - большой беспорядок. Но что комитет комитета С++, а не анализатор или имя. Удаление неоднозначности с помощью нашего инструмента выполняется автоматически, что делает эту часть действительно приятной, но если вы не заглянете внутрь наших инструментов, вы не оцените это, но мы это сделаем, потому что это означает, что небольшая инженерная команда смогла ее построить.

См. пример разрешения шаблона-vs-less, чем на наиболее раздражающем синтаксическом анализе С++, выполненном нашим парсером.