Простой интерпретатор командного языка::Журнал СА 6.2004
www.samag.ru
     
Поиск   
              
 www.samag.ru    Web  0 товаров , сумма 0 руб.
E-mail
Пароль  
 Запомнить меня
Регистрация | Забыли пароль?
Журнал "Системный администратор"
Журнал «БИТ»
Подписка
Архив номеров
Где купить
Наука и технологии
Авторам
Рекламодателям
Контакты
   

  Опросы
  Статьи

Дата-центры  

Дата-центры: есть ли опасность утечки данных?

Российские компании уже несколько лет испытывают дефицит вычислительных мощностей. Рост числа проектов,

 Читать далее...

Событие  

В банке рассола ждет сисадмина с полей фрактал-кукумбер

Читайте впечатления о слете ДСА 2024, рассказанные волонтером и участником слета

 Читать далее...

Организация бесперебойной работы  

Бесперебойная работа ИТ-инфраструктуры в режиме 24/7 Как обеспечить ее в нынешних условиях?

Год назад ИТ-компания «Крок» провела исследование «Ключевые тренды сервисного рынка 2023». Результаты

 Читать далее...

Книжная полка  

Читайте и познавайте мир технологий!

Издательство «БХВ» продолжает радовать выпуском интересных и полезных, к тому же прекрасно

 Читать далее...

СУБД PostgreSQL  

СУБД Postgres Pro

Сертификация по новым требованиям ФСТЭК и роль администратора без доступа к данным

 Читать далее...

Критическая инфраструктура  

КИИ для оператора связи. Готовы ли компании к повышению уровня кибербезопасности?

Похоже, что провайдеры и операторы связи начали забывать о требованиях законодательства

 Читать далее...

Архитектура ПО  

Архитектурные метрики. Качество архитектуры и способность системы к эволюционированию

Обычно соответствие программного продукта требованиям мы проверяем через скоуп вполне себе понятных

 Читать далее...

Как хорошо вы это знаете  

Что вам известно о разработках компании ARinteg?

Компания ARinteg (ООО «АРинтег») – системный интегратор на российском рынке ИБ –

 Читать далее...

Графические редакторы  

Рисование абстрактных гор в стиле Paper Cut

Векторный графический редактор Inkscape – яркий представитель той прослойки open source, с

 Читать далее...

День сисадмина  

Учите матчасть! Или как стать системным администратором

Лето – время не только отпусков, но и хорошая возможность определиться с профессией

 Читать далее...

День сисадмина  

Живой айтишник – это всегда движение. Остановка смерти подобна

Наши авторы рассказывают о своем опыте и дают советы начинающим системным администраторам.

 Читать далее...

Виртуализация  

Рынок решений для виртуализации

По данным «Обзора российского рынка инфраструктурного ПО и перспектив его развития», сделанного

 Читать далее...

Книжная полка  

Как стать креативным и востребованным

Издательский дом «Питер» предлагает новинки компьютерной литературы, а также книги по бизнесу

 Читать далее...

Книжная полка  

От создания сайтов до разработки и реализации API

В издательстве «БХВ» недавно вышли книги, которые будут интересны системным администраторам, создателям

 Читать далее...

1001 и 1 книга  
19.03.2018г.
Просмотров: 6227
Комментарии: 0
Машинное обучение с использованием библиотеки Н2О

 Читать далее...

12.03.2018г.
Просмотров: 6933
Комментарии: 0
Особенности киберпреступлений в России: инструменты нападения и защита информации

 Читать далее...

12.03.2018г.
Просмотров: 4217
Комментарии: 0
Глубокое обучение с точки зрения практика

 Читать далее...

12.03.2018г.
Просмотров: 3006
Комментарии: 0
Изучаем pandas

 Читать далее...

12.03.2018г.
Просмотров: 3807
Комментарии: 0
Программирование на языке Rust (Цветное издание)

 Читать далее...

19.12.2017г.
Просмотров: 3822
Комментарии: 0
Глубокое обучение

 Читать далее...

19.12.2017г.
Просмотров: 6317
Комментарии: 0
Анализ социальных медиа на Python

 Читать далее...

19.12.2017г.
Просмотров: 3172
Комментарии: 0
Основы блокчейна

 Читать далее...

19.12.2017г.
Просмотров: 3462
Комментарии: 0
Java 9. Полный обзор нововведений

 Читать далее...

16.02.2017г.
Просмотров: 7279
Комментарии: 0
Опоздавших не бывает, или книга о стеке

 Читать далее...

17.05.2016г.
Просмотров: 10647
Комментарии: 0
Теория вычислений для программистов

 Читать далее...

30.03.2015г.
Просмотров: 12366
Комментарии: 0
От математики к обобщенному программированию

 Читать далее...

18.02.2014г.
Просмотров: 14000
Комментарии: 0
Рецензия на книгу «Читаем Тьюринга»

 Читать далее...

13.02.2014г.
Просмотров: 9126
Комментарии: 0
Читайте, размышляйте, действуйте

 Читать далее...

12.02.2014г.
Просмотров: 7079
Комментарии: 0
Рисуем наши мысли

 Читать далее...

10.02.2014г.
Просмотров: 5389
Комментарии: 3
Страна в цифрах

 Читать далее...

18.12.2013г.
Просмотров: 4617
Комментарии: 0
Большие данные меняют нашу жизнь

 Читать далее...

18.12.2013г.
Просмотров: 3428
Комментарии: 0
Компьютерные технологии – корень зла для точки роста

 Читать далее...

04.12.2013г.
Просмотров: 3156
Комментарии: 0
Паутина в облаках

 Читать далее...

03.12.2013г.
Просмотров: 3402
Комментарии: 0
Рецензия на книгу «MongoDB в действии»

 Читать далее...

02.12.2013г.
Просмотров: 3027
Комментарии: 0
Не думай о минутах свысока

 Читать далее...

Друзья сайта  

 Простой интерпретатор командного языка

Архив номеров / 2004 / Выпуск №6 (19) / Простой интерпретатор командного языка

Рубрика: Программирование /  Анализ данных   | Дополнительные материалы

АЛЕКСАНДР ФЕФЕЛОВ

Простой интерпретатор командного языка

Я часто сталкиваюсь с необходимостью создания интерпретаторов командных языков и встраивания их в приложения. Под командным языком я понимаю язык, предназначенный для последовательного исполнения операторов вызова команд, описываемых простым синтаксисом:

команда [параметр1 [параметр2 ... [параметрN]]]

Языки подобного рода могут быть использованы:

  • для расширения функциональности приложений с помощью скриптов или макросов;
  • для удаленного управления приложениями (например, с помощью протокола Telnet);
  • для создания интерактивных тестовых программ.

Примерами таких языков являются язык командной строки 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 отражает наиболее общий, неспецифицический тип ошибки. Более специфические ошибки это:

  • SyntaxError – синтаксическая ошибка;
  • UnknownCommandError – неизвестная команда;
  • KnownCommandError – команда уже существует;
  • ClassNotFoundError – не найден класс, реализующий команду;
  • 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 – подробную справочную информацию. Оба метода в качестве параметра получают имя, под которым команда зарегистрирована в целевом языке.

Абстрактный интерпретатор

Разобравшись с ошибками и командами, мы можем приступить к разработке ядра нашего интерпретатора.

Структуры данных

Первым делом разберемся, как интерпретатор будет хранить данные, отражающие его состояние, – систему команд и контекст выполнения.

Система команд, с точки зрения нашего интерпретатора, – это набор пар «имя-класс», причем имена обязаны быть уникальными, а вот классы – нет. Для реализации такой структуры идеально подходит Hashtable. Им и воспользуемся.

Как хранить контекст выполнения? Для практического применения может оказаться вполне достаточной реализация понятия переменных окружения (environment variables), используемого в командных процессорах, как в UNIX, так и в DOS/Windows. Для хранения контекста также подходит Hashtable, но, поскольку и имена, и значения переменных есть строки, удобнее будет использование Properties.

package simplecli;

import java.io.*;

import java.util.*;

import simplecli.command.*;

import simplecli.error.*;

abstract public class Interpreter {

  private Hashtable commands;

  private Properties context;

  public Hashtable getCommands() {

    return commands;

  }

  public Properties getContext() {

    return context;

  }

При разбиении интерпретируемой строки на лексические элементы интерпретатор использует разделитель. Полезно будет оформить этот разделитель как полноценный член класса:

  private String delimiter; 

  public void setDelimiter(String delimiter) {

    this.delimiter = delimiter;

  }

  public String getDelimiter() {

    return delimiter;

  }

Инициализация

Инициализация интерпретатора, включающая в себя определение системы команд и начальную настройку контекста выполнения, зависит, конечно же, от системы, в которую интерпретатор будет встроен. Поэтому отдадим инициализацию на откуп абстрактным методам:

  public Interpreter() {

    context = new Properties();

    initContext(context);

    commands = new Hashtable();

    initCommands(commands);

    setDelimiter(" ");

  }

  abstract public void initContext(Properties context);

  abstract public void initCommands(Hashtable commands);

Режимы работы

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

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

Очевидно, что реализация потоковой интерпретации может быть основана на возможностях строкового режима. Поэтому начнем мы именно со строковой интерпретации:

  public String interpretClause(String clause)

    throws UnknownCommandError, CliError {

    if (clause == null) {

      return null;

    }

    clause = clause.trim();

    if (clause.length() == 0) {

      return null;

    }

    String[] tokens = tokenize(clause, getDelimiter());

    ArrayList parameters = new ArrayList();

    for (int i = 1; i < tokens.length; i++) {

      parameters.add(tokens[i]);

    }

    Command command = (Command) commands.get(tokens[0]);

    if (command == null) {

      throw new UnknownCommandError(tokens[0]);

    }

    return command.run(getContext(), parameters);

  }

  public String[] tokenize(String s, String d) {

    return s.split(d);

  }

Реализовав строковый режим, мы легко можем реализовать и потоковый:

  public void interpret(BufferedReader in,

    PrintWriter out, PrintWriter err)

    throws IOException {

    while (true) {

      String prompt = context.getProperty("$PROMPT");

      if (prompt != null && prompt.length() > 0) {

        out.print(prompt);

        out.flush();

      }

      String clause = in.readLine();

      if (clause == null) {

        break;

      }

      String result = null;

      try {

        result = interpretClause(clause);

      } catch (CliError ce) {

        err.println(ce);

        if (mustStopOnError()) {

          break;

        }

      }

      if (result != null) {

        out.println(result);

      }

      if (mustQuit()) {

        break;

      }

    }

  }

  public boolean mustQuit() {

    String quit = context.getProperty("$QUIT");

    if (quit == null) {

      return false;

    }

    if (quit.equals("yes")

      || quit.equals("true")) {

      return true;

    } else {

      return false;

    }

  }

  public boolean mustStopOnError() {

    String quit = context.getProperty("$STOPONERROR");

    if (quit == null) {

      return true;

    }

    if (quit.equals("yes")

      || quit.equals("true")) {

      return true;

    } else {

      return false;

    }

  }

Отметим пару особенностей потокового режима работы.

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

Во-вторых, что должен делать интерпретатор при обнаружении ошибки – прервать выполнение или продолжить его со следующего оператора?

Обе проблемы просто решаются с использованием контекста выполнения. Заведем в контексте специальные переменные (назовем их соответственно $QUIT и $STOPON-ERROR) и заставим интерпретатор проверять их значения после выполнения очередного оператора.

Аналогичным образом можно решить задачу выдачи приглашения ко вводу, если ввод осуществляется с консоли. Если контекстная переменная $PROMPT что-то содержит, то это «что-то» и будет использовано в качестве приглашения.

Конкретный интерпретатор

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

В качестве примера создадим конкретный интепретатор и реализуем для него простую, но мощную систему команд.

package simplecli;

import java.util.*;

import simplecli.command.*;

public class BaseInterpreter extends Interpreter {

  public void initContext(Properties context) {

    context.setProperty("$QUIT", "false");

    context.setProperty("$STOPONERROR", "false");

    context.setProperty("$PROMPT", ">");

  }

  public void initCommands(Hashtable commands) {

    commands.put("exit", new ExitCommand());

    commands.put("quit", new ExitCommand());

    commands.put("bye", new ExitCommand());

    commands.put("help", new HelpCommand(this));

    commands.put("?", new HelpCommand(this));

    commands.put("set", new SetCommand());

    commands.put("register", new RegisterCommand(this));

    commands.put("unregister", new UnregisterCommand(this));

  }

}

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

Самая простая команда – команда завершения интерпретации ExitCommand (здесь и далее я называю команды по именам классов, их реализующих). Эта команда просто меняет значение контекстной переменной $QUIT:

package simplecli.command;

import java.util.*;

import simplecli.error.*;

public class ExitCommand implements Command {

  public String run(Properties context,

    ArrayList parameters) throws SyntaxError {

    if (parameters.size() > 0) {

      throw new SyntaxError();

    }

    context.setProperty("$QUIT", "yes");

    return null;

  }

    return "Exits current interpreter session.";

  }

  public String getHelp(String name) {

    return "Exits current interpreter session."

      + CRLF + "Syntax: " + name;

  }

  private final static String CRLF =

    System.getProperty("line.separator");

}

Управление контекстом выполнения

Управляя контекстом выполнения, команды могут изменять состояние программы, в которую встроен интерпретатор, или влиять на выполнение других команд.

Для управления контекстом мы реализуем команду SetCommand, интерфейс которой схож с интерфейсом команды SET командных процессоров bash и CMD.EXE.

Вызов SetCommand без параметров будет возвращать список пар «переменная=значение» для всех переменных, определенных в контексте.

Вызов с одним параметром удалит из контекста переменную, заданную параметром.

Вызов с двумя параметрами установит переменную, указанную первым параметром, в значение, заданное вторым параметром.

package simplecli.command;

import java.util.*;

import simplecli.error.*;

public class SetCommand implements Command {

  public String run(Properties context,

    ArrayList parameters) throws SyntaxError {

    switch (parameters.size()) {

      case 0:

        // Нет параметров - возвращаем список всех

        // переменных в контексте выполнения.

        StringBuffer sb = new StringBuffer();

        Enumeration names = context.propertyNames();

        while (names.hasMoreElements()) {

           String name = (String) names.nextElement();

           String val = context.getProperty(name);

           sb.append(name + "=" + val);

           if (names.hasMoreElements()) {

             sb.append(CRLF);

           }

        }

        if (sb.length() > 0) {

          return sb.toString();

        } else {

          return null;

        }

      case 1:

        // Один параметр - удаляем из контекста выполнения

        // переменную, указанную в качестве параметра.

        context.remove((String) parameters.get(0));

        return null;

      case 2:

        // Два параметра - устанавливаем в контексте

        // выполнения переменную, указанную в качестве

        // первого параметра, в значение, указанное

        // в качестве второго параметра.

        context.setProperty((String) parameters.get(0),

          (String) parameters.get(1));

        return null;

      default:

        throw new SyntaxError();

    }

  }

    return "Manages environment variables.";

  }

  public String getHelp(String name) {

    return "Manages environment variables."

      + CRLF + "Syntax: " + name + " [variable [value]]";

  }

  private final static String CRLF =

    System.getProperty("line.separator");

}

Побочным эффектом изменения контекста может быть влияние на процесс интерпретации. Например, описанная выше команда завершения интерпретации может быть реализована непосредственно на целевом языке:

set $QUIT true

Система помощи

Интерфейс Command предоставляет возможности для создания справочной системы. На основе этих возможностей мы и запрограммируем команду HelpCommand. Вызов команды HelpCommand без параметров возвратит список всех зарегистрированных команд с кратким описанием каждой из них, а вызов с одним параметром выдаст подробную справку по команде, имя которой задано параметром.

package simplecli.command;

import java.util.*;

import simplecli.*;

import simplecli.error.*; 

public class HelpCommand implements Command {

  public HelpCommand(Interpreter interpreter) {

    this.interpreter = interpreter;

  }

  public String run(Properties context,

    ArrayList parameters)

    throws SyntaxError, UnknownCommandError {

    switch (parameters.size()) {

      case 0: {

        // Нет параметров - возвращаем краткое описание

        // всех известных команд.

        StringBuffer sb = new StringBuffer();

        Hashtable commands = interpreter.getCommands();

        Enumeration names = commands.keys();

        while (names.hasMoreElements()) {

           String name = (String) names.nextElement();

           Command cmd = (Command) commands.get(name);

           sb.append(name + " " + descr);

           if (names.hasMoreElements()) {

             sb.append(CRLF);

           }

        }

        if (sb.length() > 0) {

          return sb.toString();

        } else {

          return null;

        }

      }

      case 1: {

        // Один параметр - возвращаем полную справочную

        // информацию по команде, указанной в качестве

        // параметра.

        String name = (String) parameters.get(0);

        Hashtable commands = interpreter.getCommands();

        Command cmd = (Command) commands.get(name);

        if (cmd == null) {

          throw new UnknownCommandError(name);

        }

        return cmd.getHelp(name);

      }

      default:

        throw new SyntaxError();

    }

  }

    return "Prints help infomation.";

  }

  public String getHelp(String name) {

    return "Prints help infomation."

      + CRLF + "Syntax: " + name + " [command]";

  }

  private Interpreter interpreter;

  private final static String CRLF =

    System.getProperty("line.separator");

}

Динамическое изменение системы команд

Посмотрев на код нашего конкретного интерпретатора, можно заметить, что система команд целевого языка фиксируется еще на этапе компиляции кода. Это не очень гибкое решение.

Конечно же, можно переписать метод initCommands так, чтобы он создавал систему команд «на лету», считывая ее описание из конфигурационного файла.

Но более интересным решением может оказаться встраивание возможности изменения системы команд непосредственно в целевой язык.

Давайте закодируем пару команд RegisterCommand/UnregisterCommand, первая из которых будет добавлять команду к системе команд, а вторая – удалять ее оттуда.

Команда RegisterCommand должна вызываться с двумя обязательными параметрами. Первый – имя, под которым будет зарегистрирована новая команда. Второй – полностью квалифицированное имя класса, реализующего новую команду, причем этот класс должен удовлетворять ряду ограничений:

  • класс должен реализовывать интерфейс Command;
  • класс должен предоставлять конструктор без параметров;
  • класс должен быть доступен для Java VM через CLASSPATH.

package simplecli.command; 

import java.util.*; 

import simplecli.*;

import simplecli.error.*; 

public class RegisterCommand implements Command {

  public RegisterCommand(Interpreter interpreter) {

    this.interpreter = interpreter;

  }

  public String run(Properties context,

    ArrayList parameters) throws SyntaxError,

    KnownCommandError, ClassNotFoundError, ClassCastError {

    if (parameters.size() != 2) {

      throw new SyntaxError();

    }

    String name = (String) parameters.get(0);

    String clazzName = (String) parameters.get(1);

    Hashtable commands = interpreter.getCommands();

    if (commands.containsKey(name)) {

      throw new KnownCommandError();

    }

    Class clazz = null;

    try {

      clazz = Class.forName(clazzName);

    } catch (ClassNotFoundException cnfe) {

      throw new ClassNotFoundError();

    }

    Command command = null;

    try {

      command = (Command) clazz.newInstance();

    } catch (Exception e) {

      throw new ClassCastError();

    }

    commands.put(name, command);

    return null;

  }

    return "Registers new command.";

  }

  public String getHelp(String name) {

    return "Registers new command."

      + CRLF + "Syntax: " + name + " command class";

  }

  private Interpreter interpreter;

  private final static String CRLF =

    System.getProperty("line.separator");

}

У команды UnregisterCommand всего один параметр, который задает команду, подлежащую удалению из системы команд.

package simplecli.command;

import java.util.*;

import simplecli.*;

import simplecli.error.*;

public class UnregisterCommand implements Command {

  public UnregisterCommand(Interpreter interpreter) {

    this.interpreter = interpreter;

  }

  public String run(Properties context,

    ArrayList parameters)

    throws SyntaxError, UnknownCommandError {

    if (parameters.size() != 1) {

      throw new SyntaxError();

    }

    String name = (String) parameters.get(0);

    Hashtable commands = interpreter.getCommands();

    if (commands.remove(name) == null) {

      throw new UnknownCommandError();

    }

    return null;

  }

    return "Unregisters command.";

  }

  public String getHelp(String name) {

    return "Unregisters command."

      + CRLF + "Syntax: " + name + " command";

  }

  private Interpreter interpreter;

  private final static String CRLF =

    System.getProperty("line.separator");

}

Испытательный полигон

Вот все работы и завершены. Теперь самое время увидеть интерпретатор в действии.

package simpleclitest;

import java.io.*;

import simplecli.*;

public class BaseInterpreterTest {

  public static void main(String[] args)

    throws IOException {

    System.out.println("BaseInterpreter testbed");

    BufferedReader in = new BufferedReader(

      new InputStreamReader(System.in));

    PrintWriter out = new PrintWriter(System.out, true);

    Interpreter interpreter = new BaseInterpreter();

    interpreter.interpret(in, out, out);

  }

}

Компилируем, запускаем, экспериментируем:

BaseInterpreter testbed

>help 

bye     Exits current interpreter session.
quit    Exits current interpreter session.
?       Prints help infomation.
help    Prints help infomation.
exit    Exits current interpreter session.
unregister      Unregisters command.
register        Registers new command.
set     Manages environment variables.

>help set

Manages environment variables.
Syntax: set [variable [value]]

Поиграем с командой set:

>set

$PROMPT=>
$QUIT=false
$STOPONERROR=false 

>set $PROMPT #

#set VAR val

#set

$PROMPT=#
VAR=val
$QUIT=false
$STOPONERROR=false

#set VAR

#set

$PROMPT=#
$QUIT=false
$STOPONERROR=false

Удалим set из системы команд:

#unregister set

#set

simplecli.error.UnknownCommandError: set

Вернем set обратно:

#register set simplecli.command.SetCommand

Зарегистрировать уже существующую команду не удастся:

#register set simplecli.command.SetCommand

simplecli.error.KnownCommandError

Также не удастся зарегистрировать команды, реализуемые несуществующими или неподходящими классами:

#register wrong String

simplecli.error.ClassNotFoundError

#register wrong java.lang.String

simplecli.error.ClassCastError

Ну и напоследок:

#bye


Комментарии отсутствуют

Добавить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

               Copyright © Системный администратор

Яндекс.Метрика
Tel.: (499) 277-12-45
E-mail: sa@samag.ru