Для заданного языка определяет представление его грамматики, а также интерпретатор предложений языка, использующий это представление.
Назначение
Для заданного языка определяет представление его грамматики, а тек же интерпретатор предложений этого языка.
Применимость
Используйте паттерн интерпретатор, когда есть язык интерпретации, предложение которого можно представить в виде абстрактных синтаксических деревьев. Лучше всего этот паттерн работает, когда:
- грамматика проста. Для сложных грамматик иерархия классов становится слишком грамоздкой и неуправляемой. В таких случаях лучше применять генераторы синтаксических анализаторов, поскольку они могут могут интерпретировать выражения, не строя абстрактных синтаксических деревьев, что экономит память, а возможно, и время;
- эффективность не является главным критерием. Наиболее эффективные интерпретаторы обычно не работают непосредственно с деревьями, я сначала транслируют их в другую форму. Так регулярное выражение часто преобразуют в конечный автомат. Но даже в этом случае сам транслятор можно реализовать с помощью паттерна интерпретатор.
Результаты
Плюсы
- грамматику легко изменять и расширять. Поскольку для представления грамматических правил в паттерне используются классы, то для изменения или расширения грамматики можно применять наследование. Существующие выражения можно модифицировать постепенно, а новые определять как вариации старых;
- простая реализация грамматики.Реализации классов, описывающих узлы абстрактного синтаксического дерева, похожи. Такие классы легко кодировать, а зачастую их может автоматически сгенерировать компилятор или генератор синтаксических анализаторов;
- добавление новых способов интерпретации выражений. Паттерн интерпретатор позволяет легко изменить способ вычисления выражений. Например, реализовать красивую печать выражения вместо проверки входящих в него типов можно, просто определив новую операцию в классах выражений. Если вам приходится часто создавать новые способы интерпретации выражений, подумайте о применении паттерна Посетитель. Это поможет избежать изменения классов описывающих грамматику.
Минусы
- сложные грамматики трудно сопровождать. В паттерне интерпретатор определяется по меньшей мере один класс для каждого правила грамматики. Поэтому сопровождение грамматики с большим числом правил иногда оказывается трудной задачей. Для ее решения могут быть применены другие паттерны. Но если грамматика очень сложна, лучше прибегнуть к другим методам, например воспользоваться генератором компиляторов или синтаксических анализаторов;
Реализация
У реализации паттернов интерпретатор и компоновщик есть много общего. Следующие вопросы относятся только к интерпретатору:
- создание абстрактного синтаксического дерева. Паттерн интерпретатор не поясняет, как создавать дерево, то есть разбор выражения не входит в его задачу. Создать дерево разбора может таблично-управляемый или написанный вручную (обычно методом рекурсивного спуска) анализатор, а так сам клиент;
- определение операции Interpret. Определять операцию Interpret в классах выражений необязательно. Если создавать новые интерпретаторы приходится часто, то лучше воспользоваться паттерном Посетитель и поместить операцию Interpret в отдельный объект-посетитель. Например, для грамматики языка программирования будет нужно определить много операций над абстрактными синтаксическими деревьями: проверку типов, оптимизацию, генерацию кода и т.д. Лучше, конечно, использовать посетителя и не определять эти операции в каждом классе грамматики;
- разделение терминальных символов с помощью паттерна приспособленец. Для грамматик , предложения которых содержат много вхождений одного и того же терминального символа, может оказаться полезным разделение этого символа. Хорошим примером служат грамматики компьютерных программ, поскольку в них каждая переменная встречается в коде многократно. В терминальных узлах обычно не хранится информация о положении в абстрактном синтаксическим дереве. Необходимый для интерпретации контекст предоставляют им родительские узлы. Налицо различие между разделяемым (внутренним) и передаваемым (внешним) состояниями, так что вполне применим паттерн приспособленец.
Структура
Участники
AbstractExpression - абстрактное выражение: объявляет абстрактную операцию Interpret, общую для всех узлов в абстрактном синтаксическом дереве;
TerminalExpression - терминальное выражение: реализует операцию Interpret для терминальных символов грамматики. Необходим отдельный экземпляр для каждого терминального символа в предложении.
NontеrminalExpression - нетерминальное выражение: по одному такому классу требуется для каждого грамматического правила R :: = R1 R2 ... Rn. Хранит переменные экземпляра типа AbstractExpression для каждого символа от R1 до Rn. Реализует операцию Interpret для нетерминальных символов грамматики. Эта операция рекурсивно вызывает себя же для переменных, представляющих R1,...Rn
Context - контекст: содержит информацию, глобальную по отношению к интерпретатору.
Client - клиент: строит (или получает в готовом виде) абстрактное синтаксическое дерево, представляющее отдельное предложение на языка с данной грамматикой. Дерево составлено из экземпляров классов NontеrminalExpression и TеrminalExpression. Вызывает операцию Interpret