Научная статья на тему 'Автоматическое завершение ввода условий в диаграммах состояний'

Автоматическое завершение ввода условий в диаграммах состояний Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
305
39
i Надоели баннеры? Вы всегда можете отключить рекламу.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Шалыто Анатолий Абрамович, Мазин Максим Александрович, Гуров Вадим Сергеевич

Описан процесс разработки системы автоматического завершения ввода условий на переходах в диаграммах состояний для программного пакета с открытым кодом UniMod. Основой этой системы является автомат Мили, который строится по грамматике, описывающей язык, используемый при задании условий на переходах.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Auto-completion of guard condition expressions in state charts

This article describes the process of developing an auto-completion system for guard conditions on transitions in state charts diagrams for open-source proj ect UniMod. The base of this system is the Mealy automaton built using guard conditions language grammar.

Текст научной работы на тему «Автоматическое завершение ввода условий в диаграммах состояний»

ПРОГРАММНЫЕ И АППАРАТНЫЕ СРЕДСТВА X

УДК 681.3.06

АВТОМАТИЧЕСКОЕ ЗАВЕРШЕНИЕ ВВОДА УСЛОВИЙ В ДИАГРАММАХ СОСТОЯНИЙ

В. С. Гуров,

ведущий разработчик М. А. Мазин,

ведущий разработчик

Компания ООО «Интелли Джей Лабс»

А. А. Шалыто,

доктор техн. наук, профессор Санкт-Петербургский государственный университет информационных технологий, механики и оптики

Описан процесс разработки системы автоматического завершения ввода условий на переходах в диаграммах состояний для программного пакета с открытым кодом UniMod. Основой этой системы является автомат Мили, который строится по грамматике, описывающей язык, используемый при задании условий на переходах.

Введение

В работе [1] предложен метод проектирования событийных объектно-ориентированных программ с явным выделением состояний, названный «SWITCH-технология» или «автоматно-ориентированное программирование». Особенность этого подхода состоит в том, что поведение таких программ описывается с помощью графов переходов структурных конечных автоматов с нотацией, предложенной в работе [2]. SWITCH-технология для описания каждого автомата определяет два типа диаграмм (схема связей и граф переходов). При наличии нескольких автоматов также строится схема взаимодействия автоматов. SWITCH-технология задает нотацию и операционную семантику используемых диаграмм.

Программный пакет с открытым кодом UniMod (http://unimod.sf.net), созданный авторами статьи [3], обеспечивает разработку и выполнение автоматно-ориентированных программ. Этот пакет позволяет использовать UML-нотацию при построении диаграмм в рамках SWITCH-технологии. При этом схемы связей, определяющие интерфейс автоматов, строятся в нотации диаграмм классов языка UML, а графы переходов — в UML-нотации диаграмм состояний. В состав пакета UniMod входит встраиваемый модуль (plug-in) для платформы Eclipse (http://www.eclipse.org), позволяющий создавать и редактировать UML-диаграммы классов и состояний, которые соответствуют схеме связей и графу переходов.

Как отмечено в работе [3], интегрированные системы для разработки программ предоставляют удобные средства для работы с кодом, такие как, например:

• подсветка семантических и синтаксических ошибок;

• автоматическое завершение ввода и автоматическое исправление ошибок;

• форматирование и рефакторинг кода [4];

• запуск и отладка программы внутри среды разработки.

В английском языке эти средства получили название «code assist».

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

Постановка задачи

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

Например, на рис. 1 показано, что среда разработки Eclipse при нажатии сочетания клавиш Ctrl-

■ Рис. 1. Пример автоматического завершения ввода

Space после строки текста t. предлагает на выбор варианты автоматического завершения ввода.

Сформулируем требования к проектируемой системе автоматического завершения ввода. Пусть задан язык L и на вход системы подана строка а.

1. Если строка а является префиксом некоторого предложения языка L (Эю: аmeL), то система должна возвращать множество строк

С(а) = Ш;=1..„,

любая из которых может являться продолжением строки а. Изложенное может быть записано соотношением вида

Vie [1..n]Эу: аР;ye L.

2. Если строка а не является префиксом предложения на заданном языке (Vm: аюе L), то система должна с помощью дополнения строки недостающими символами или удаления лишних символов трансформировать строку в правильный префикс предложения языка. Количество дополнений и удалений должно быть как можно меньше.

Элементы теории построения компиляторов, применяемые в настоящей работе

Если исходный язык L задан порождающей грамматикой, то для построения такой системы необходимо использовать методы проектирования компиляторов [5]. Существует множество инструментов для автоматического создания компиляторов по заданной грамматике (http://www.kulichki.net/ kit/tools/java.html). На рис. 2 приведена обобщенная структура компилятора.

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

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

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

В проекте UniMod условия на переходах являются логическими формулами, в которых могут использоваться предикаты первого порядка определенного вида. Трансляция этих условий выполняется с помощью так называемого «компилятора компиляторов» ANTRL [6]. Он по заданной LL^-грамматике строит код на языке Java, реализующий лексический анализатор и рекурсивный нисходящий синтаксический анализатор [5]. Построенный синтаксический анализатор может быть использован и как распознаватель принадлежности выражения заданному грамматикой языку, и как транслятор выражений в абстрактное синтаксическое дерево. Данный анализатор не может быть применен для построения системы автоматического завершения ввода, так как в случае подачи ему на вход префикса для выражения на заданном языке вместо законченного выражения он выдает ошибку.

Существуют различные подходы к реализации требуемой системы. Одним из таких подходов является использование управляемого таблицей разбора нерекурсивного нисходящего синтаксического анализатора, построенного на основе автомата с магазинной памятью [5]. Граф переходов такого автомата имеет одну вершину и много петель.

Таблица разбора представляет собой двумерный массив M[A, a], где A — нетерминал, a — терминал (лексема) или символ конца потока $. В ячейках таблицы записываются продукции грамматики, с помощью которых заменяются нетерминалы на вершине стека. Пустые ячейки таблицы означают ошибки.

При подаче на вход этому анализатору строки а без символа конца потока анализатор остановится, имея какой-то нетерминал на вершине стека. В этом случае множество терминалов ^а), ожидаемых после обработанной строки, может быть определено как {в: M[T, в] Ф 0}, где T — нетерминал на вершине стека после остановки анализатора.

Для реализации восстановления после ошибок в «режиме паники» [5] таблица разбора может быть дополнена синхронизирующими символами, которые вписываются в некоторые пустые ячей-

Поток

символов

Рис. 2. Обобщенная структура компилятора

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

В работе [7] показано, как создать программу нерекурсивного нисходящего синтаксического анализатора, используя автоматный подход. При этом таблица разбора применяется в роли объекта управления.

Цель настоящей работы состоит в создании системы автоматического завершения ввода, позволяющей исключить таблицу разбора нисходящего нерекурсивного синтаксического анализатора, которую строить трудно.

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

Описание предлагаемого подхода

Предлагаемый подход состоит в том, что для заданной контекстно-свободной грамматики типа LL(1) строится конечный автомат Мили, который будет являться синтаксическим анализатором.

В отличие от классического подхода предлагается этот автомат строить как реагирующий на события, что объясняется тем, что в дальнейшем автомат будет реализован диаграммой состояний языка UML, которая по спецификации является событийной [8]. Поэтому автомат будет реагировать на события, которые поставляет ему лексический анализатор. Каждому событию соответствует терминал.

В работах [5, 9] нисходящий синтаксический анализатор также строится на основе диаграмм состояний, однако, в отличие от предлагаемого подхода:

• для каждого правила вывода, входящего в описание грамматики, строится одна диаграмма;

• в таких диаграммах отсутствуют события и выходные воздействия. Отсутствие выходных воздействий объясняется наличием срединной рекурсии, которая появляется на диаграммах, строящихся для правил вывода вида 5 ^ а5Ь;

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

• в указанных выше работах реализация диаграмм не описывается.

Описываемый в настоящей статье подход предлагает сворачивать все диаграммы в одну, при необходимости удаляя срединную рекурсию с помощью метода, описанного в работе [10]. Это дает возможность избавиться от упоминания нетерми-

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

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

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

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

Пусть LL(1 )-грамматика для нашего примера задана следующим множеством правил вывода:

1. S ^ else | T S'

2. S' ^ or T S' | e

3. T ^ L T'

4. T' ^ and L T' | e

5. L ^ not L | P

6. P ^ ‘(’ S ‘)’ | int rel N | bool | N P'

7. P' ^ rel int | e

8. N ^ id dot id

Терминал id соответствует идентификатору, int — целочисленной константе, bool — булевской константе, rel — бинарному отношению (‘>’, ‘<’, ‘>=’, ‘<=’, ‘=’, V’), терминалы and, or, not — булевским операциям, терминал else — оператор «иначе». Опишем формальный процесс построения автомата Мили для данной грамматики.

На рис. 3 для каждого нетерминала заданной грамматики показаны диаграммы состояний, построенные с помощью метода, описанного в работе [5]. Приведенные диаграммы, со сквозной нумерацией состояний, отличаются от аналогичных диаграмм, используемых в работе [5], наличием начального и конечного состояний. Из начального состояния всегда существует только один переход. В конечное состояние также всегда ведет один переход.

Состояния в приведенных диаграммах соответствуют позициям [11] в правилах вывода, метки на переходах — терминалам и нетерминалам, отделяющим позиции друг от друга. Если нетерминал выводит e-правило (пустое), то из состояния, соответствующего начальной позиции, существует непомеченный переход в состояние, соответствующее конечной позиции. Непомеченные переходы называются также немотивированными.

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

©-►

0 1 . 1 S' 2

else T

г.

©—►

10

nd

О-»

он*.

14

15

16

24

rel.

25

¡п!

26

©-►

17

11

18

20

©—►

27

28

dot

29

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

id.

30

S'.

12

13

V

19

V- -/

rel

21

22

23

bool

Рис. 3. Диаграммы состояний для каждого нетерминала грамматики

Рис. 4. Удаление правой рекурсии на диаграмме состояний для нетерминала 5

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

• удаление правой рекурсии;

• удаление немотивированных переходов;

• подстановка диаграмм состояний друг в друга;

• удаление срединной рекурсии.

Опишем каждый из этих шагов.

Удаление правой рекурсии

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

Например, правая рекурсия в правиле 2 приводит к наличию перехода из состояния 5 в состояние 6 на соответствующей диаграмме состояний (см. рис. 3). Для устранения этой рекурсии указанный переход заменим немотивированным переходом в состояние, соответствующее начальной позиции, — в состояние 3 (рис. 4).

Удаление немотивированных переходов

Наличие немотивированного перехода из состояния в состояние означает, что за позицией, соответствующей состоянию ф£, могут следовать те же терминалы и нетерминалы, что и за позицией, соответствующей состоянию 5].

Для устранения немотивированного перехода выполняются следующие операции:

• создается составное состояние 5^, исходящие дуги которого заменяют одинаковые исходящие дуги для всех вложенных состояний [8];

• состояния и 5] помещаются внутрь состояния

• все переходы из состояния заменяются аналогичными переходами из состояния 5].

На рис. 5 показано удаление немотивированного перехода из состояния 5 в состояние 3 (см. рис. 4).

Диаграмма на рис. 5 может быть упрощена за счет ликвидации эквивалентных состояний 3 и 5, имеющих одинаковые исходящие переходы (рис. 6).

Отметим, что это преобразование аналогично вычеркиванию одинаковых записей из таблицы, задающей функцию переходов автомата при минимизации числа состояний в нем [12].

Теперь удалим немотивированный переход в полученной диаграмме (рис. 7).

Рис. 5. Удаление немотивированного перехода из состояния 5 в состояние 3

©—►

3, 5

Рис. 6. Упрощение диаграммы состояний, показанной на рис. 5

T

or

3

4

5

6

L

L

T

7

8

9

L

no

P

N

N

id

T

4

6

or

3, 5, 6 t—^ —*m

T Ju 4

I3, 5J- -°+

Рис. 7. Удаление немотивированного перехода из состояния 3, 5 в состояние 6

Рис. 8. Преобразованная диаграмма состояний для нетерминала S'

Т fl4, 16

not

4r

7 r > PH 9

14, 15

16

tJ

not

Рис. 9. Подстановка диаграмм состояний друг в друга

Состояние 6 (см. рис. 7) не имеет входящих переходов и, следовательно, не достижимо. Поэтому может быть удалено. После его удаления в состоянии 3,5,6 остается одно вложенное состояние 3,5. Начала переходов, исходящих из состояния 3, 5, 6, следует перенести в состояние 3, 5, а само состояние 3, 5, 6 удалить, так как оно теперь не имеет исходящих переходов. В результате получается диаграмма состояний для нетерминала Б' (рис. 8).

Подстановка диаграмм состояний друг в друга

Количество диаграмм состояний может быть сокращено путем подстановки одних диаграмм в другие, что может привести, в том числе, и к одной диаграмме.

Предположим, что на диаграмме для нетерминала N существует переход из состояния Б, в состояние Б], помеченный нетерминалом Nj. Заменим такой переход на немотивированный из состояния Б, в состояние, следующее за начальным на диаграмме состояний для нетерминала N. Добавим переход из состояния, предшествующего конечному, на диаграмме состояний для нетерминала N]в состояние Б]. Отметим, что указанную подстановку требуется выполнять, только если эти нетерминалы разные (^ Ф Nj). Это объясняется тем, что в противном случае имеет место срединная рекурсия, удаление которой будет описано ниже.

После выполнения такой подстановки возникшие немотивированные переходы следует устранить, как описано выше. При этом сначала устраняется немотивированный переход из состояния Б,, а затем немотивированный переход в состояние Б].

Рис. 9 иллюстрирует подстановку диаграммы состояний для нетерминала Ь в диаграмму состояний для нетерминала Т.

На рис. 10 показана диаграмма состояний после устранения немотивированных переходов.

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

Если некоторый нетерминал N присутствует на диаграмме для нетерминала N] более одного раза, то каждый переход, помеченный символом N1, необходимо заменить соответствующей диаграммой состояний. В результате количество однотипных подграфов на диаграмме N чрезмерно возрастает.

Предлагается преобразовать диаграмму N таким образом, чтобы нетерминал N встречался на ней минимальное число раз. Для этого использу-

not

Рис. 10. Устранение немотивированных переходов после подстановки

else

0

V. /

1, 3, 5,2

♦И, 3, 5

else

0, 4

1, 3, 5,2

1, 3, 5

Рис. 11. Удаление однотипных переходов

P

T

or

4

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

T

T

2

or

4

T

or

0

4

■ Рис. 12. Диаграмма состояний для рассматриваемой грамматики

ется следующий подход: если несколько переходов, помеченных нетерминалом N1, ведут в одно и то же состояние Б, то можно выделить составное состояние и заменить все эти переходы единственным переходом, помеченным нетерминалом N который исходит из группового состояния и входит в состояние Б.

На рис. 11 данный подход применен для диаграммы состояний нетерминала Б. Из рисунка следует, что два перехода, помеченных нетерминалом Т, преобразованы в один переход.

Для описанной выше грамматики исходное множество диаграмм (см. рис. 3) преобразуется в одну диаграмму, приведенную на рис. 12.

Поясним внутренний переход в крайнем левом составном состоянии. Он заменяет два перехода —

из верхнего состояния в нижнее и петлю в нижнем состоянии.

В заключение отметим, что на полученной диаграмме присутствует срединная рекурсия — переход из состояния 18 в состояние 19, так как дуга между этими состояниями помечена нетерминалом Б — нетерминалом, для которого построена эта диаграмма в целом.

Удаление срединной рекурсии

Для удаления срединной рекурсии предлагается использовать подход, предложенный в работе [10], который основан на явном применении стека:

• пусть на диаграмме состояний для нетерминала N существует рекурсивный переход из состояний Б, в состояние Б], помеченный нетерминалом N;

Рис. 13. Диаграмма состояний с удаленной срединной рекурсией

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

• на первом переходе должно выполняться действие по добавлению в стек метки МБ], соответствующей исходному целевому состоянию Б], а на втором переходе — действие по извлечению метки МБ] из стека при условии, что эта метка находится на вершине стека.

Таким образом, на диаграмме состояний появятся действия, которые воздействуют на стек.

На рис. 13 показана диаграмма, приведенная на рис. 12, с удаленной срединной рекурсией и появившимися действиями, выполняемыми на переходах (автомат Мили).

Таким образом, заданную грамматику удалось заменить одной диаграммой состояний.

Использование построенной диаграммы

Будем строить систему автоматического завершения ввода с помощью инструментального средства UniMod [3, 13, 14]. Отметим, что здесь имеет место «рекурсия», так как рассматриваемая система для инструментального средства UniMod строится с помощью этого же средства.

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

Рис. 14. Схема связей автомата

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

На рис. 14 приведена схема связей для рассматриваемого примера. В ней слева показан лексический анализатор, в центре — автомат, а справа — стек. При программировании источник событий и объект управления реализуются каждый своим классом. При этом в соответствии с работой [3] код для автомата может и не строиться, так как автомат может интерпретироваться.

На рис. 15 показана UML-диаграмма состояний автомата, построенная на основе диаграммы, приведенной на рис. 13, с помощью замены терминалов событиями и замены действий на переходах ссылками на методы объекта управления о1. Состояния 18 и 19 на рис. 15 отсутствуют из-за удаления немотивированных переходов.

Полученная модель системы состоит из двух UML-диаграмм (см. рис. 14, 15) и описывает распознаватель для языка, заданного приведенной выше грамматикой. Отметим, что информация о приоритете операций была потеряна в ходе

(: e3/o1 .z2

0, 4, 7, 11, 14, 15, 17, 27

0,

18

4, 7, 11, 14, 15

not: e11

else: e12

or: e7

ап<± е6

Id: e5 С ----------►

28

dot: e10.

29

Id: e5

bool: el

И: е2

): e4[o1 .x2] /o1 .z1

1, 3, 5, 2

► 2

23, 24, 26, 16, 8...

30, 23, 24

30, 24, 26

21

rel: e

22, 27

Id: e5

28

dot: е1(

29

Id: e5

eof: e9

rel: e8

25

T

И: е2

Рис. 15. Диаграмма состояний автомата

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

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

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

Восстановление после ошибок

Перейдем к реализации второго требования, предъявляемого к системе, — обработке ошибочных строк. Для этого автомат А необходимо модифицировать таким образом, чтобы он корректно восстанавливался в случае подачи на вход выражения, не являющегося префиксом какого-либо выражения, принадлежащего языку. При этом автомат должен всегда останавливаться в состоянии, в которое существует переход по событию, соответствующему последнему терминалу, извлеченному из поданного на вход выражения.

Существует несколько возможных вариантов реализации восстановления автомата после ошибки. Например, можно для каждого состояния добавить такой исходящий переход, ведущий в конечное «ошибочное» состояние, что он будет срабатывать в случае отсутствия какого-либо другого исходящего перехода для пришедшего события и текущих значений входных переменных. Это приведет к тому, что при появлении в процессе распознавания первого же ошибочного терминала автомат завершит работу в «ошибочном» состоянии. Однако из «ошибочного» состояния нет исходящих переходов, и, следовательно, множество возможных последующих терминалов будет пустым.

Авторы предлагают использовать альтернативный алгоритм обработки ошибочных ситуаций, основанный на локально оптимальной коррекции входного потока терминалов от лексического анализатора. Такой подход называют также восстановлением на уровне фразы [5].

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

Для того чтобы автомат А, находясь в состоянии Б, пропустил в потоке терминал, соответствующий пришедшему событию е, необходимо добавить в автомат петлю в состоянии Б по событию е. Тогда, находясь в состоянии Б и получив событие е, автомат останется в состоянии Б — проигнорирует пришедшее событие и как следствие пропустит терминал в потоке.

Для того чтобы автомат А, находясь в состоянии Б, дополнил поток недостающими терминалами, следует выполнить указанные ниже операции:

1) найти достижимое из Б состояние Бк такое, что в нем существует исходящий переход по событию е. Если из состояния Б достижимы несколько таких состояний, то выберем ближайшее из них;

2) если из ближайшего найденного состояния Бн есть переход в некоторое состояние Б{ по событию е при условии с, то необходимо добавить в автомат переход из состояния Б в состояние Б{ по событию е при условии с. Отметим, что отсутствие условия трактуется как тождественная истина.

Последовательность терминалов, соответствующих событиям, которыми помечен кратчайший путь из состояния Б в состояние Б*, можно использовать для вставки в поток перед терминалом, соответствующим пришедшему событию е.

Если лексический анализатор позволяет заглядывать на произвольное количество терминалов вперед, то можно применять оба способа коррекции одновременно, выбирая оптимальный способ в процессе разбора.

Для выбора оптимального способа авторы предлагают использовать следующее правило:

1) при получении ошибочного терминала в текущем состоянии вычислим количество терминалов, которыми нужно дополнить поток;

2) вычислим количество терминалов, которое нужно пропустить в потоке, до следующего обрабатываемого в текущем состоянии терминала;

3) выполним коррекцию, требуемое количество терминалов для которой минимально.

Для реализации этого способа коррекции к автомату А распознавателя в качестве объекта управления добавим лексический анализатор (рис. 16).

Рис. 16. Схема связей модели распознавателя с лексическим анализатором в качестве объекта управления

Рис. 17. Добавление переходов, корректирующих поток, в состояние 21

Лексический анализатор предоставляет автомату распознавателя целочисленную входную переменную o2.x1. Ее значение равно числу терминалов, которые необходимо пропустить в потоке, до следующего терминала, обрабатываемого в текущем состоянии. Если входной поток вообще не содержит терминалов, обрабатываемых в текущем состоянии, то значение переменной o2.x1 больше любого наперед заданного целого числа.

В автомат А добавляются переходы, реализующие и добавление, и пропуск терминалов в потоке. Переходы, реализующие дополнение потока, помечаются следующим условием: длина пути из состояния S в состояние Sh меньше или равна значению входной переменной o2.x1 . Переходы, реализующие пропуск терминалов, помечаются отрицанием того же условия. Если для состояния S не существует состояния Sh, то переход, удаляющий лексему, выполняется безусловно.

Например, в состоянии 21 нет переходов по событию e10 — в этом состоянии появление во входном потоке терминала dot (точка) не ожидается. Для того чтобы обработать ошибочное появление этого терминала, необходимо добавить два перехода, исходящих из состояния 21 (рис. 17). Ближайшее состояние, в котором обрабатывается событие e10, — состояние 28. Длина пути из состояния 21 в состояние 28 равна двум. Поэтому условие на петле в состоянии 21 по событию e10 имеет вид o1.x1 < 2. Таким образом, в случае, если сразу за терминалом dot в потоке следует терминал rel (отношение), то терминал dot игнорируется. Если следует какой-нибудь другой терминал, то целесообразно сразу перейти в состояние 29, т. е. добавить в поток отсутствующие терминалы rel и id (идентификатор).

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

состояний, так как ближайшее состояние, в котором обрабатывается неожидаемый терминал для данного состояния, можно вычислить, используя, например, алгоритм Флойда—Уоршала [15].

Получение множества строк

для автоматического завершения ввода

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

После того, как автомат распознавателя, дополненный корректирующими переходами, обработает все терминалы, извлеченные из поданного на вход выражения, он окажется в некотором состоянии S. Для построения множества вариантов завершения следует определить множество переходов, исходящих из S, условия на которых при текущих значениях входных переменных истинны. Терминалы, соответствующие событиям, которыми помечены эти переходы, должны быть преобразованы обратно во множество строк. Например, терминал id должен быть преобразован во множество имен переменных, а терминал and — в строку «&&». Полученное множество строк и будет множеством вариантов завершения.

Пример работы системы

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Приведем пример построения множества вариантов завершения.

Пусть на вход распознавателю подана строка

! ol.xl &&.

Лексический анализатор преобразует ее в поток терминалов

not id dot id and,

которому соответствует последовательность событий

Рис. 18. Пример автоматического завершения ввода

ell, e5, elü,e5,e6.

В процессе обработки этих событий автомат изменяет состояния в следующем порядке:

(0,18^(4,7,11,14,15)^(28)^(29)^

^(30,23,24)^(4,7,11,14,15).

Состояние (4,7,11,14,15), в котором остановился автомат, содержит исходящие переходы для событий

e1, e2, e3,e5,e11.

Этим событиям соответствуют терминалы bool, int, '(', id, not, которые преобразуются в строки:

"true", "false", "(", "o1", "o2", "o22", "!".

Литература

1. Шалыто А. А., Туккель Н. И. Танки и автоматы // BYTE/Россия. 2003. № 2. С. 69-73. http://is.ifmo.ru/ works/tanks_new/

2. Шалыто А. А., Туккель Н. И. SWITCH-технология — автоматный подход к созданию программного обеспечения «реактивных» систем //Программирование. 2001. № 5. С. 45-62. http://is.ifmo.ru/works/ switch/1/

3. Гуров В. С., Мазин М. А., Нарвский А. С., Шалыто А. А. UML. SWITCH-технология. Eclipse //Информаци-онно-управляющие системы. 2004. № 6. С. 12-17.

4. Фаулер М. Рефакторинг. Улучшение существующего кода. М.: Символ-Плюс, 2003. 623 с.

5. Ахо А., Сети Р., Ульман Д. Компиляторы: принципы, технологии и инструменты. М.: Вильямс, 2001. 768 с.

6. Parr T. J., Quong R. W. ANTRL: A Predicated-LL(k) Parser Generator // Software — Practice And Experience. 1995. N 25 (7). P. 789-810.

7. Шалыто А. А., Штучкин А. А. Совместное использование теории построения компиляторов и SWITCH-технологии (на примере построения калькулятора). http://is.ifmo.ru/projects/calc/

Эти строки и формируют множество вариантов завершения для строки, поданной на вход распознавателю.

На рис. 18 показан фрагмент среды разработки с встроенной системой автоматического завершения ввода, описанной в настоящей статье.

Заключение

В работе [5] отмечено, что нерекурсивные нисходящие синтаксические анализаторы можно строить, используя диаграммы состояний, записанные для каждого нетерминала исходной грамматики. Настоящая работа предлагает подход для построения всего одной диаграммы состояний для исходной грамматики. На базе построенной диаграммы реализуется система автоматического завершения ввода. Также отметим, что в известной авторам литературе описание формального метода построения подобных систем отсутствует. Данная работа устраняет указанный пробел.

Реализация системы автоматического завершения ввода для следующей версии проекта UniMod выполнена с помощью предыдущей версии проекта, вследствие чего часть проектной документации была получена «автоматически», так как диаграммы, созданные с помощью UniMod-редактора, являются автоматными программами и могут быть включены в проектную документацию без изменений. Создание последующих версий средств разработки с помощью предыдущих является общепринятой практикой и позволяет говорить о зрелости программного продукта.

8. Буч Г., Рамбо Г., Якобсон И. UML. Руководство пользователя. М.: ДМК, 2000. 358 с.

9. Легалов А. И. Основы разработки трансляторов. Использование диаграмм Вирта для представления динамически порождаемых конечных автоматов, распознающих КС(1) грамматику. http://softcraft.ru/ translat/lect/t08-04.shtml

10. Шалыто А. А., Туккель Н. И., Шамгунов Н. Н. Реализация рекурсивных алгоритмов на основе автоматного подхода //Телекоммуникации и информатизация образования. 2002. № 5. С. 72-99. http:// is.ifmo.ru/works/recurse/

11. Хантер Р. Основные концепции компиляторов. М.: Вильямс. 2002. 256 с.

12. Акимов О. Е. Дискретная математика: логика, группы, графы. М.: Лаборатория Базовых Знаний, 2003. 376 с.

13. Гуров В. С., Нарвский А. С., Шалыто А. А. Исполняемый UML из России //PC Week/RE. 2005. № 26. С. 18, 19.

14. UniMod. http://unimod.sf.net

15. Кормен Т., Лайзерсон Ч., Ривест Р. Алгоритмы. Построение и анализ. М.: МЦМНО, 2000. 9б0 с.

i Надоели баннеры? Вы всегда можете отключить рекламу.