Обычно невозможно выполнить расширение макроса внутри синтаксического анализатора, по крайней мере, не макросы в стиле C, поскольку расширение макроса в стиле C не учитывает синтаксис. Например,
#define IF if(
#define THEN )
является законным (хотя ИМХО очень плохой стиль). Но для того, чтобы это обрабатывалось внутри грамматики, было бы необходимо позволить макроидентификатору появляться где угодно во входных данных, а не только там, где можно ожидать идентификатора. Необходимые изменения в грамматике сделают ее намного менее читабельной и, скорее всего, приведут к конфликтам действий синтаксического анализатора. [Примечание 1]
В качестве альтернативы, вы можете выполнить расширение макроса в лексическом анализаторе. Лексический анализатор не является синтаксическим анализатором, но синтаксический анализ вызова макроса в стиле C не требует особой сложности, и если бы параметры макроса не были разрешены, это было бы еще проще. Вот как Flex обрабатывает замену макросов в своих регулярных выражениях. ({identifier}
, например. [Примечание 2] Поскольку макросы Flex представляют собой просто необработанные символьные последовательности, а не списки токенов, как в макросах в стиле C, их можно обработать, вставив замещающий текст обратно во входной поток. (F ) lex предоставляет специальное действие unput
для этой цели. unput
возвращает один символ обратно во входной поток, поэтому, если вы хотите извлечь sh замену всего макроса, вам нужно unput
это один символ за раз, вперед, так что последний символ unput
будет первым, который будет прочитан впоследствии.
Это выполнимо, но уродливо. И это не очень масштабируемо даже для небольшого списка возможностей предоставляется препроцессором C, и это нарушает основополагающий принцип разработки программного обеспечения, который заключается в том, что каждый компонент выполняет только одну функцию (чтобы он мог делать это хорошо).
Таким образом, остается наиболее распространенный подход , то есть добавить отдельный компонент макропроцессора, чтобы вместо разделения анализа на лексическое сканирование / синтаксический анализ, анализ стал лексическое сканирование / расширение макроса / синтаксический анализ. [Примечание 3]
Макропроцессор в стиле C, который работает между лексическим анализатором и анализатором syntacti c, сам может быть написан на языке Bison. Как я упоминал выше, требования к синтаксическому анализу, как правило, минимальны, но анализ еще предстоит выполнить, и Bison, по-видимому, уже является частью проекта. Хотя я не знаю ни одного макропроцессора (кроме программ для проверки концепции, которые я сам написал), я думаю, что это очень гибкое решение. В частности, фаза анализа Bison syntacti c может быть реализована с помощью pu sh -parser, что устраняет необходимость в генерации всего макрокомпенсированного потока токенов, чтобы сделать его доступным для традиционного pull-парсера.
Однако это не единственный способ создания макросов. Действительно, у него много недостатков, потому что расширения макросов не hygieni c, не соблюдая ни синтаксис, ни область видимости. Вероятно, кто-то, кто использовал макросы C, однажды был укушен этими проблемами; простейшим проявлением является определение макроса, например:
#define NEXT(a) a + 1
, а затем запись
int x = NEXT(a) * 3;
, которая не приведет к ожидаемому результату (если то, что ожидается, не является нарушением синтаксиса c форма последнего утверждения). Кроме того, любое расширение макроса, которому необходимо использовать локальную переменную, рано или поздно приведет к неправильному расширению из-за неожиданного конфликта имен. Расширение макроса Hygieni c стремится решить эти проблемы, рассматривая расширение макроса как операцию с деревьями синтаксиса, а не с потоками токенов, создавая лексическое сканирование / анализ синтаксиса / расширение синтаксического анализа парадигмы (дерева разбора). Для этой операции подходящим инструментом может быть какой-то синтаксический анализатор дерева.
Примечания
Кроме того, вы хотите удалить токен из Дерево разбора Yacc / bison имеет плохо документированную функцию YYBACKUP, которая может помочь в достижении этого sh. Я не знаю, является ли это одним из предполагаемых вариантов использования; действительно, мне не ясно, каковы предполагаемые варианты использования.
Документация (f) lex называет эти определения , но они действительно являются макросами, и они страдают от всех обычных проблем, которые несут с собой макросы, таких как таинственное взаимодействие с окружающим синтаксисом.
Другая возможность - это расширение макроса / лексическое сканирование / синтаксический анализ, который может быть реализован с использованием макропроцессор типа М4. Но это полностью отделяет макросы от остальной части языка.