Написать собственный интерпретатор синтаксиса в Java? - PullRequest
4 голосов
/ 24 сентября 2011

Я собираюсь начать писать демонстрационную программу для лекции, которую я собираюсь прочитать.Я хочу позволить каждому ученику в классе загрузить это приложение, а затем иметь возможность создавать экземпляры объектов (и их графические представления) в интерактивном режиме с помощью командной строки.Я решил писать на java не потому, что это язык, с которым я больше всего знаком, а потому, что у него простые графические классы, и я могу быть уверен, что jar будет работать на их компьютерах.

Введение закончено.Теперь вопрос:

Каков хороший способ реализовать какой-либо собственный синтаксис командной строки для этой программы?Я хочу использовать простой, произвольный синтаксис, такой как:

CREATE Monster Bob;    
Bob.jump();   
LS Bob //to list Bob's methods or something.   
LS CREATE //to list all the classes    

Сначала я расскажу о том, что впервые пришло в голову, когда я подумал об этой проблеме.

Я могу себе представить, что у меня может быть набор карт в древовидной связи.Я мог бы разобрать каждое ключевое слово как ключ к следующей карте.Таким образом, «CREATE Monster Bob» можно оценить как

1) Поиск карты ключевых слов для ключа «CREATE».Вернуть значение, являющееся ссылкой на карту классов.2) Поиск карты классов по ключу "Монстр".Вернуть значение, которое является классом фабрики, реализующим некоторый интерфейс Leaf, который позволяет мне знать, что это значение листа (я проверю, используя instanceof).
3) Возможно, интерфейс Leaf будет содержать метод с именем execute (), который будетделай что хочешь.В этом случае он создал бы объект Monster, добавив этот объект на карту под названием Objects с именем Bob.(Это дело Листа звучит некрасиво, но его можно убрать.)

Круто.Но это утверждение немного сложнее для меня: Bob.jump ();

1) Поиск какой-либо карты объектов для «Боба».Вернуть некоторый объект, реализующий интерфейс с методом, подобным «define (String s)», и передать ему строку «jump ()»
2) Боб ищет некоторую внутреннюю карту методов для «jump ()», затем ...?В c ++ ключом должен быть указатель на функцию-член Monster.jump (), которая будет выполняться.Но я не верю, что в Java нет такой вещи, как указатель на функцию.Я читал, что вы можете использовать анонимный класс для достижения этой цели, хотя я не пробовал.Похоже, это будет работать.

Итак, это будет работать, но есть ли более элегантный способ сделать это?Я никогда раньше не писал никаких интерпретаторов.Я хотел бы сделать это хорошим способом и узнать что-то в процессе, если у кого-то есть какие-то советы.Это выглядит как потенциально подверженный ошибкам способ сделать что-то, если я не очень структурирован, особенно когда Боб и любой другой объект начинают анализировать свои собственные инструкции и использовать анонимные функции.Кроме того, похоже, что каждому классу потребуется интерфейс, готовый к выполнению, кроме обычного кода.

Я также не очень хорошо знаю Java, поэтому, если есть некоторые места, где я могу столкнуться с кирпичной стеной, тогда я тоже хотел бы знать.

Спасибо за помощь заранее.

Ответы [ 3 ]

11 голосов
/ 24 сентября 2011

Я бы на самом деле предложил использовать Python - если нет действительно хорошей причины не делать этого.

Это потому что:

  1. В Python есть действительно приятно IDE / REPL с именем IDLE .Я не могу сказать достаточно об использовании хорошего Read-Eval-Print-Loop : цикл обратной связи short очень хорош для обучения / игры.Любители приключений могут даже начать прыгать!
  2. Поддержка графики является кросс-платформенной и хорошо поддерживается через TkInter .
  3. Я считаю, что это лучший язык для начинающих и / илине программисты, чем Java.(Python на самом деле не мой любимый язык, но он очень удобен для новичков и, опять же, имеет очень хорошую IDE / REPL.)
  4. Это намного меньше работает для вас; -)

Вот как может выглядеть код Python для демонстрации:

Bob = BigMonster()
Bob.jump()
dir(Bob)
dir(Monters)

Поскольку все это всего лишь обычный синтаксис Python нет синтаксического анализа - просто создайте несколько классов, возможно, реализуйте протокол __dir__, и все готово к работе.Если требуется интеграция с Java, существует также Jython , хотя я никогда не пробовал этого с IDLE (или знаю, поддерживается ли он как таковой).

Удачное кодирование.

Основанный на изображениях SmallTalk , такой как Sqeak , на далеко более интерактивен, чем Python, поскольку код является частью постоянной рабочей среды.Тем не менее, требуется некоторое время, чтобы найти хорошее изображение - Squeak вряд ли является лучшей реализацией, но оно бесплатное - и изучить конкретную среду SmallTalk.Таким образом, хотя интеграция может в конечном итоге привести к большим выплатам, она требует большей акклиматизации:)


Но, увы, для использования простого синтаксического анализатора на Java, они будут интересны:

  1. A лексер , который превращает введенный текст в поток токенов, и;
  2. и синтаксический анализатор рекурсивного спуска (это действительно простой подход для разбора)который либо
    1. создает AST (абстрактное синтаксическое дерево) , по которому можно пройти (читай: "запустить") позже, либо;
    2. или "делает вещи" прямо сейчас(немедленная оценка)

Парсер простого рекурсивного спуска - это вводный курс по Java для ознакомления с приведенными выше понятиями. Вот некоторый код для парсера рекурсивного спуска для "синтаксиса нейтрино", что бы это ни было - посмотрите на комментарии и насколько хорошо парсер рекурсивного спуска может соответствовать грамматике EBNF.

Теперь, это просто вопрос определения семантических правил этого псевдо / мини-языка и его реализации; -)


Немного изучив семантику / подход Javaнемного больше (части - просто упрощение / переформулировка оригинального сообщения):

CREATE Monster Bob

Создаст новый MonsterObject.Некоторые подходы могут быть:

  1. Создать объект с отражением , или;
  2. карта классов Factory (из String -> FactoryObject), как говорилось,или;
  3. простая статическая ветвь if-else.

Результат будет сохранен в «переменном хеше», который отображает Name -> MonsterObject.

Bob.jump()

Выполните синтаксический анализ для [object Bob] [method jump] [p1], [p2], ..., [pn], найдите объект в "хэше переменных" и затем:

  1. Используйте отражение, чтобы вызвать метод или;
  2. иметь карту (полученную с помощью метода MonsterObject) для Name -> MethodEvaluatorObject (например, имеет eval(Object ... params) метод) или
  3. вызывать метод вида eval(String action, String[] ... parameters) и иметь егоиспользуйте ветвь if-else, чтобы «делать вещи» (обратите внимание, что параметры, если таковые имеются, уже выделяются во время синтаксического анализа).

LS Bob и LS Monster полагаются на хороший бито том, как реализованы два предыдущих.

Хотя в Java нет «указателей на функции», их можно эмулировать с помощью объектов с заданным интерфейсом (то есть сами объекты функционируют как указатели). Функциональная Java имеет классы F / F2 /.../ F8 , чтобы попытаться обработать это единообразно с помощью обобщений. Однако в Java обычно существует отдельный одноразовый интерфейс (или класс), такой как Runnable с одним методом «action», который изменяется, чтобы принимать соответствующие параметры и возвращать соответствующий результат (такой как MethodEvaluatorObjects или FactoryObjects).

Если есть какие-либо специфические вопросы по одной из тем (рефлексия, рекурсивный спуск, анонимные типы, [эмулированные] замыкания и т. Д.), То не стесняйтесь задавать другой ТАК вопрос с специфическим фокусом. (И, как всегда, должная осмотрительность в исследованиях окупается; -)

2 голосов
/ 24 сентября 2011

Если вы действительно не собираетесь создавать новый язык программирования, вы можете просто разбить команды на части (используя пробел в качестве разделителя), а затем выполнить поиск для первой части: CREATE Monster Bob; => create, monster, bob:

String operation = parts[0];
if(operation.equals(`create`)) {
  String type = parts[1];
  String name = parts[2];
  // your logic here
} else if(operation.equals(`...`)) {
  ...
}
1 голос
/ 24 сентября 2011

Рассматривали ли вы использовать генератор синтаксического анализатора, как ANTLR?Он может создавать синтаксические анализаторы для многих типов языков и выводить синтаксический анализатор на различных языках, включая Java.Это может значительно ускорить вашу задачу, и программное обеспечение бесплатно (хотя книги продаются, но, эй, ваше время чего-то стоит, верно?).

http://en.wikipedia.org/wiki/ANTLR

НаС другой стороны, вы могли бы, вероятно, свернуть свой собственный анализатор для простого языка, о котором говорит PST, но я бы не стал его слишком усложнять.Просто создайте себе функцию, которая разбивает файл на строковые токены (лексеры), и другую, которая запрашивает токен за раз и определяет, что с ним делать.Если ваш язык прост, этого может быть достаточно.

...