Вход на хостинг
IT-новости
20.04.2016 iPhone 2017 года поместят в водонепроницаемый корпус из стекла
Линейка iPhone в новом году серьезно поменяется. В этом уверен аналитический исследователь Мин Чи Ку......
30.07.2015 Ищем уникальный контент для сайта
Ищем уникальный контент для сайта Без уникального контента Ваш сайт обречен на то, что его страницы......
Александр Фефелов
Я часто сталкиваюсь с необходимостью создания интерпретаторов командных языков и встраивания их в приложения. Под командным языком я понимаю язык, предназначенный для последовательного исполнения операторов вызова команд, описываемых простым синтаксисом:
команда [параметр1 [параметр2 ... [параметрN]]]
Языки подобного рода могут быть использованы:
n для расширения функциональности приложений с помощью скриптов или макросов;
n для удаленного управления приложениями (например, с помощью протокола Telnet);
n для создания интерактивных тестовых программ.
Примерами таких языков являются язык командной строки ftp-клиента или языки управления столь распространенными сейчас DSL-модемами.
В этой статье я предложу простое решение, которое позволит вам с минимальными трудозатратами создать интерпретатор для командного языка. В качестве языка программирования я буду использовать Java.
Intro
Итак, имеется некоторый язык (далее будем называть его целевым), поддерживающий только один оператор – оператор вызова команды. Программы на этом языке записываются в виде последовательности строк, причем в одной строке может быть расположен только один оператор. Система команд целевого языка полностью определена решаемой задачей.
Необходимо для этого языка создать интерпретатор, который, получив очередной оператор, будет выполнять его и возвращать результат выполнения.
Возможно, результат выполнения текущего оператора будет зависеть от результатов выполнения предыдущих операторов или от состояния приложения, в которое встроен интерпретатор. Например, в том же ftp-клиенте нельзя получить файл командой get, если перед этим не было установлено соединение с сервером. Поэтому, интерпретатор должен поддерживать понятие контекста исполнения, причем одним из результатов выполнения оператора может быть изменение этого контекста.
Ошибки
Начнем с ошибок. Для обработки ошибок, возникающих в процессе работы интерпретатора, создадим несложную иерархию исключений. Корнем этой иерархии будет исключение CliError:
package simplecli.error;
public class CliError extends Exception {
public CliError() {
}
public CliError(String msg) {
super(msg);
}
}
Все остальные исключения нашей иерахии являются наследниками CliError и реализуются аналогичным образом.
CliError отражает наиболее общий, неспецифицический тип ошибки. Более специфические ошибки это:
n SyntaxError – синтаксическая ошибка;
n UnknownCommandError – неизвестная команда;
n KnownCommandError – команда уже существует;
n ClassNotFoundError – не найден класс, реализующий команду;
n ClassCastError – класс не может реализовывать команду.
Команды
У всех команд целевого языка, как бы ни различались алгоритмы их работы, есть одно общее важное свойство – способность к выполнению с определенным набором параметров в определенном контексте. Отразим это в интерфейсе Command:
package simplecli.command;
import java.util.*;
import simplecli.error.*;
public interface Command {
String run(Properties context, ArrayList parameters)
throws CliError;
Для выполнения команды интерпретатор вызывает метод run, передавая ему экземпляр ArrayList, содержащий в виде объектов String параметры вызова команды, и экземпляр Properties, отражающий текущее состояние контекста выполнения (см. ниже). Результат выполнения команды возвращается в виде строки.
В реальном целевом языке хотелось бы иметь поддержку системы помощи, хотя бы и в минимальном объеме. Это пригодится в интерактивном режиме работы. Поэтому добавим в интерфейс Command пару методов:
String getDescription(String name);
String getHelp(String name);
}
Метод getDescription должен возвращать краткое описание команды, а метод getHelp – подробную справочную информацию. Оба метода в качестве параметра получают имя, под которым команда зарегистрирована в целевом языке.
Абстрактный интерпретатор
Разобравшись с ошибками и командами, мы можем приступить к разработке ядра нашего интерпретатора.
Структуры данных