Сравнивайте с английским: нажмите на абзац — оригинал откроется в окне. Кнопка EN под абзацем показывает его прямо в тексте.
Содержание
Введение
В компьютерном программировании, "хак лексера" — распространённое решение проблем при разборе ANSI C, вызванное тем, что эталонная грамматика чувствительна к контексту. В языке C для определения, является ли последовательность символов именем переменной или именем типа, требуется учет контекста синтаксической структуры, что делает невозможным использование контекстно-свободного лексера.
In computer programming, the lexer hack is a common solution to the problems in parsing ANSI C, due to the reference grammar being context sensitive. In C, classifying a sequence of characters as a variable name or a type name requires contextual information of the phrase structure, which prevents one from having a context free lexer.
Решение для взлома
Решение обычно заключается в передаче информации из таблицы семантических символов обратно в лексер. То есть, вместо функционирования как однонаправленный конвейер от лексера к парсеру, существует обратный канал от семантического анализа к лексеру. Такое смешение синтаксического и семантического анализа обычно считается неэлегантным, поэтому это называют "хаком". Без дополнительного контекста лексер не может отличить идентификаторы типов от других идентификаторов, поскольку все идентификаторы имеют одинаковый формат. Благодаря этому хаку, в приведенном выше примере, когда лексер обнаруживает идентификатор A, он должен иметь возможность классифицировать токен как идентификатор типа. Правила языка можно было бы уточнить, указав, что приведение типов требует идентификатор типа, и неоднозначность исчезла бы. Эта проблема также существует в C++, и парсеры могут использовать тот же хак. Парсер Clang обрабатывает эту ситуацию совершенно иначе, используя нереференциальную лексическую грамматику. Лексер Clang не пытается различать имена типов и имена переменных: он просто сообщает текущий токен как идентификатор. Затем парсер использует библиотеку семантического анализа Clang для определения природы идентификатора. Это обеспечивает более четкое разделение ответственности и инкапсуляцию лексера и парсера, и поэтому некоторые разработчики компиляторов считают это гораздо более элегантным решением, чем "хак лексера". Этот подход также используется в большинстве других современных языков, которые не различают различные классы идентификаторов в лексической грамматике, а вместо этого откладывают их определение на фазу синтаксического или семантического анализа, когда доступно достаточно информации.
The solution generally consists of feeding information from the semantic symbol table back into the lexer. That is, rather than functioning as a pure one way pipeline from the lexer to the parser, there is a backchannel from semantic analysis back to the lexer. This mixing of parsing and semantic analysis is generally regarded as inelegant, which is why it is called a "hack". Without added context, the lexer cannot distinguish type identifiers from other identifiers because all identifiers have the same format. With the hack in the above example, when the lexer finds the identifier A it should be able to classify the token as a type identifier. The rules of the language would be clarified by specifying that typecasts require a type identifier and the ambiguity disappears. The problem also exists in C++ and parsers can use the same hack. The Clang parser handles the situation in a completely different way, namely by using a non reference lexical grammar. Clang's lexer does not attempt to differentiate between type names and variable names: it simply reports the current token as an identifier. The parser then uses Clang's semantic analysis library to determine the nature of the identifier. This allows a much cleaner separation of concerns and encapsulation of the lexer and parser, and is therefore considered by some compiler developers to be a much more elegant solution than The Lexer Hack. This is also the approach used in most other modern languages, which do not distinguish different classes of identifiers in the lexical grammar, but instead defer them to the parsing or semantic analysis phase, when sufficient information is available.