Минимизация трансляционной КСР-грамматики и состояний синтаксического анализатора КСР-языка

УДК 681.51

© Л.Н. Федорченко

МИНИМИЗАЦИЯ ТРАНСЛЯЦИОННОЙ КСР-ГРАММАТИКИ И СОСТОЯНИЙ СИНТАКСИЧЕСКОГО АНАЛИЗАТОРА КСР-ЯЗЫКА

В статье представлены алгоритмы, выполняющие минимизацию регулярных выражений в правилах трансляционной грамматики и состояний таблиц анализатора языка как заключительный этап метода регуляризации КСР-грамматик, который реализован в инструментальной системе SynGT (Syntax Graph Transformation).

Ключевые слова: эквивалентные преобразования грамматик, КСР-грамматика.

О L.N. Fedorchenko

MINIMIZATION OF TRANSLATIONAL CFR-GRAMMAR AND CONDITIONS OF GENERATED PARSER CFR-LANGUAGE

The paper presents algorithms that perform minimization of regular expressions within the rules of translational grammar and conditions of parser language tables as a final stage of regulation method of CFR-grammar, which is implemented in the special tool system SynGT (Syntax Graph Transformations).

Keywords: equivalent transformation of grammar, CFR-grammar.

Введение

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

Однако грамматику, преобразованную к регулярной форме (регуляри-зованную), можно получить из исходной автоматически. Для этой цели существует программное решение - инструментальная система SynGT (Syntax Graph Transformations), которая с помощью встроенной схемы эквивалентных преобразований правил грамматики позволяет трансформировать произвольную КС-грамматику, представляемую в форме BNF (Backus-Naur Form) или EBNF (Extended Backus-Naur Form) [1], превратив ее в трансляционную КС-грамматику е регулярной

форме (КСР-грамматику), по которой синтезируется анализатор языка с линейной временной сложностью и улучшенными, по сравнению с известными системами из семейства компиляторов GNU, характеристиками по эффективности и объему памяти.

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

1. Регуляризация КС-грамматики

Известно [1-2], что под регуляризацией контекстно-свободной грамматики (КС-грамматики) понимается процесс ее последовательного эквивалентного преобразования таким образом, что в результате получают трансляционную КСР-грамматику (КС-грамматику в регулярной форме), правила которой (КСР-правила) представляют собой обобщенные регулярные выражения относительно символов всех алфавитов исходной грамматики [2-4]. В этом случае соответствующий языковой процессор работает как семейство конечных автоматов (связанных друг с другом), каждый из которых распознает свой фрагмент входной цепочки языка, порождаемый полученной (после преобразования) грамматикой.

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

Завершающей фазой процесса регуляризации является минимизация записи регулярных выражений КСР-правил и последующая минимизация состояний синтезированного распознавателя.

Минимизация записи грамматики позволяет добиться представления правил с помощью наименьшего количества вхождений символов в правило. Использование бинарной операции обобщенной итерации (#) (вместо обычной итерации Клини (*)) уже на начальных этапах преобразований частично минимизирует запись правил.

В соответствии с данными в [2-4] определениями множество в конечном алфавите V регулярно тогда и только тогда, когда оно либо 0, либо { в } (в - пустая цепочка символов), либо { а } для некоторого символа а е V , либо его можно получить из этих множеств, применяя конечное число раз операции объединения, конкатенации, унарной и бинарной обобщенной итерации (#). Операция обобщенной итерации не расширяет множество регулярных слов, определяемых обобщенным регулярным выражением. Она может быть определена через традиционную операцию Клини (*) как P#Q = P,(Q,P)* . Такое применение обобщенной итерации в записи

регулярных выражений частично решает задачу минимизации регулярного выражения по числу вхождений символов из объединенного алфавита терминалов, нетерминалов, семантик (в формуле: слева - два вхождения символа, справа - три вхождения), таким образом, уменьшая вероятность появления конфликта Shift/Reduce при построении анализатора языка.

2. Схема минимизации регулярных выражений

Минимизированная грамматика строится с помощью преобразования исходного множества правил к регулярному виду посредством применения эквивалентных преобразований, затем - минимизации таблиц синтезированного автомата и, наконец, выполнения обратного преобразования для получения окончательного эквивалентного регулярного выражения. Ra ==> ГА ==> /.ЖА/ ==> min R ,. где

Ra - регулярное выражение КСР-правила для нетерминала А в объединенном алфавите терминалов, нетерминалов и семантик; ГА - граф-схема регулярного выражения RA, минимизированная по

вхождениям символов из объединенного алфавита; DKAr - детерминированный конечный автомат, построенный из ГА и

минимизированный по числу состояний; min Ra - регулярное выражение, полученное обратным преобразованием из конечного автомата DKAr .

1 А

Для получения минимальной КСР-грамматики необходимо получить минимальные регулярные выражения для всех КСР-правил. Таким образом, на вход программной системы подается КСР-грамматика G , на выходе - получаем минимизированный детерминированный конечный автомат DKAT, по которому обратным преобразованием строятся регулярные выражения для КСР-правил.

На рисунке 1 в качестве примера рассмотрим КСР-грамматику G.

G:

А : ' а ' # 'Ь ' ; (А, ' с ' # ' d ' ) #В.

В : ' с ' # ' d ' .

Рис. 1. Пример КСР-грамматики для синтеза конечного автомата

Построим синтаксическую граф-схему (СГС) Гс = {/' ,, Гв } для грамматики G и состояния автомата в соответствии с определением состояния в СГС (регулярный случай).

А

В

4-ту

Рис. 2. СГС для КСР-грамматики О

3. Построение конечного автомата по регулярному выражению

В данном случае для конечного автомата все вершины имеют одинаковый статус (не различаем терминальные и нетерминальные вершины). Семантики отсутствуют.

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

Переход от одной компоненты СГС к другой управляется магазином, содержащим нетерминалы грамматики. Напомним определение состояния из [2], которым воспользуемся для примера.

Определение 1. Состоянием в ГА называется:

1) либо выходная вершина в ГА . Обозначим ее через /',;

2) либо терминальная (нетерминальная) вершина ГЛ ;

3) либо объединение состояний в Гл .

Для произвольной вершины /? , где /? - не выходная вершина /',, (Р ФРЛ), определим состояние вершины /3 в ГА как множество вершин, смежных с вершиной р. <5(3={ ос | а - вершина в граф-схеме /', и а е 5мсс(/?) }.

Если р - входная вершина (обозначение Ел), то 8^ - начальное состояние графа ГЛ, которое является начальным состоянием конечного автомата 1)КЛГ . Из определения 1 следует, что начальным состоянием является множество вершин, которые достижимы из входной вершины Ел .

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

Определенное выше состояние в графе ГА по содержанию тождественно понятию состояния конечного автомата из [1].

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

Пусть S - состояние в ГА и £ - символ (текущая буква входного слова) из алфавита терминалов и нетерминалов.

Определение 2. Для состояния S «переходом по символу» с, будем

называть состояние S / % в ГА , в котором:

1) если S = {FJ или S = 0,to S/£ = 0;

Г0 прит(а)Ф%,

2) если S = {а} , а - вершина в ГА , то S / £ = <

[Sa при т(а) =

где т(а) - метка вершины а ;

3) если S = (J<S, ,то S/4 = [jSl/4.

¿=1 ¿=1

Таким образом, в результате применения операции «перехода по символу» получаем переходное состояние как объединение состояний тех вершин, которые помечены этим символом в рассматриваемом состоянии. Если состояние пусто или отсутствуют помеченные вершины, то переходное состояние также пусто. Когда переходное состояние пусто, это означает, что данный символ (в качестве следующей буквы анализируемого слова) недопустим.

Для грамматики G (рис. 1) построенные состояния вершин следующие:

SEA={a,A};Sa={b,FA};SA={c};Sb={a};Sc={d,B,FA};SB={A};

4. Модуль минимизации состояний

Рассмотрим классы модуля минимизации состояний распознавателя, построенного по граф-схеме для отдельных КСР-правил и реализованных в SynGT.

TStatesSet - класс для представления множества состояний - ячейка в таблице переходов. Реализован при помощи стандартного типа Delphi set (множество), отсюда максимальное количество состояний автомата не должно превышать 256. Этого достаточно для грамматик с не более 265 символами для каждого правила. Для увеличения количества вершин в СГС возможно коррекция класса на основе собственного типа (не встроенного в Borland Delphi), не меняя при этом интерфейса класса TStatesSet. Описание класса приводится на рисунке 3.

TMinimizationTable - класс-представление детерминированного автомата в виде таблицы переходов. Класс позволяет динамически наполнять таблицу состояний-переходов с помощью вызовов методов создания состояний (createState) и их связывания (linkStates).

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

Наиболее важной функцией в интерфейсе класса TMinimizationTable является собственно минимизация таблицы состояний (функция minimize). При ее вызове для построенного автомата происходит преобразование таблицы по числу переходов к минимальному виду, изоморфному исходной таблице.

Собственно минимизация происходит следующим образом:

1. Организуется цикл по списку строк таблицы.

2. В цикле делается попытка объединить любые 2 строки таблицы состояний.

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

Функции CanJoin2Rows и Join2Rows возвращают логическое значение, определяющее возможность объединения двух строк таблицы. Затем выполняется или не выполняется объединение состояний соответственно этому значению.

Функция CanJoin2Rows работает по следующему алгоритму:

1. Если множество удаленных состояний содержит одно из объединяемых состояний, то объединение невозможно.

2. Если любая из строк соответствует конечному состоянию, то объединение невозможно.

3. Производится обход обеих строк по всем символам, входящим в состояние, и сравниваются множества состояний в каждой ячейке таблицы. Если эти множества совпадают за исключением тех состояний, для которых производится сравнение, то объединение возможно.

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

TStatesSet = class

public

constructor Create(MaxStatesCount: integer);

\\

function findState(statelndex: integer): boolean;

procedure addState(statelndex: integer);

\\

function Count: integer;

function getDataSet: ByteSet;

procedure setDataSet(adata: ByteSet);

private

data: ByteSet;

end;

Рис. 3. Описание класса TStatesSet 44

Функция Join2Rows вызывается для пары состояний, для которых CanJoin2Rows вернула значение true. Она работает по следующему алгоритму:

1. В цикле объединяемые строки таблицы состояний сливаются в первой строке (состоянии) с вычетом номера состояния, соответствующего второй строке.

2. Номер второго состояния добавляется в список deletedStatesSet - удаленных состояний.

3. Производится замена номера второго состояния на номер первого по всей таблице (replaceState).

4. После вызова функции minimize объект типа TMinimizationTable содержит минимизированную таблицу состояний.

На рисунках 4-9 даны описания класса минимизации состояний таблицы конечного автомата, реализованного в SynGT.

TMinimizationTable = class public

constructor Create(MaxStatesCount, MaxSymbolsCount:

integer) ;

destructor Dispose;

function createState(): TState;

procedure linkStates(a, b: TState; s: TSymbol); procedure minimize; {Методы доступа к таблице}

function isEnptyState(statelndex: integer): boolean; function getStatesCount: integer; function getSymbolsCount: integer; function getStateName(index: integer): string; function getSymbol(index: integer): string; function getTableElement(statelndex, symbollndex: integer): TStatesSet;

procedure WriteToFile(filename: string); protected

procedure addState(startStatelndex, symbollndex: integer; endStatelndex: integer);

function findstate(state: TState): integer; function findSymbol(symbol: TSymbol): integer; function AddNewSymbol(s: TSymbol): integer; function AddNewState(s: TState): integer; function CanJoin2Rows(rowl,row2: integer): boolean; procedure Join2Rows(rowl,row2: integer); procedure replaceState(oldState: integer; newState: integer);

private

data: array of array of TStatesSet; states: array of TState; symbols: array of TSymbol; nextState: TState; emptyStatesSet: TStatesSet; statesCount, symbolsCount: integer; end;

Рис.4. Пример класса минимизации состояний таблицы анализатора

5. Служебные модули минимизации в SynGT

1. TChildForm.Minimize: формирование правил в строковом представлении, вызов TransTransformation со строкой-грамматикой.

2. TransTransformation.Minimize: загрузка грамматики из строки, вызов TGrammar.Minimize.

3. TGrammar.Minimize: цикл по всем правилам; рекурсивное построение таблицы минимизации для нетерминала TRE_Tree.buildMinimizationTable(minTable, minRec), здесь minTable - это таблица минимизации типа TMinimizationTable (см. выше), minRec -структура минимизации типа TMinRecord; вызов minTable.minimize; построение нового правила на основе минимизированной таблицы:

4. TRETree.buildMinimizationTable (а также во всех потомках: TRE And, TRE Or, TRE Iteration, TRE Nonterminal, TRE Leaf и ДР-)-

Таблица минимизации строится рекурсивным обходом дерева для правила грамматики с базовым классом TRE_Tree:

TRE_Tree = class(TComponent) private

{ Private declarations } public

{ Public declarations }

function equals(aTree :TRE_Tree):boolean;virtual; function isEmptyO:boolean;virtual;

// ...

procedure buildMinimizationTable(var table: TMinimizationTable; minRec:TMinRecord) ;virtual;abstract; end;

Рис. 5. Пример служебного модуля

Для построения таблицы переходов автомата используется структура TMinRecord на рис. 6.

TMinRecord = record start, finish: TState; end;

Рис. 6. Структура для построения таблицы переходов состояний Эта структура содержит номера стартового и конечного состояний для данного поддерева.

Структура передается как параметр в функцию buildMinimizationTable узла дерева с уже заданными значениями для начального и конечного состояния. Внутри функции для узла вычисляются промежуточные состояния, необходимые для представления дерева выражений в виде таблицы переходов автомата. Например, при построении таблицы для TRE_Or (операции «или») процедура минимизации вызывается для левого и правого операндов с одними и теми же номерами стартового и конечного состояния (на рис. 7).

procedure TRE_Or.buildMinimizationTable(var table:TMinimizationTable; minRec:TMinRecord); begin

m_Leftpperand.buildMinimizationTable(table, minRec); m_Rightpperand.buildMinimizationTable(table, minRec); end;

Рис. 7. Пример вызова процедуры минимизации для операции «или»

Для операции TRE_And (операция «и») сначала строится таблица состояний для левого поддерева, а затем конечное состояние для левого поддерева используется как стартовое для правого поддерева:

procedure TRE_And.buildMinimizationTable (var table:TMinimizationTable; minRec:TMinRecord); var

finish: TState; begin

finish := minRec.finish;

minRec.finish := table.createState();

m_Leftpperand.buildMinimizationTable(table, minRec);

minRec.start := minRec.finish;

minRec.finish := finish;

m_Rightpperand.buildMinimizationTable(table, minRec); end;

Рис. 8. Пример вызова процедуры минимизации для операции «и»

Реализация функции для операции построения таблицы минимизации для TRE_Iteration (обобщенная бинарная итерация) приведена на рисунке 9. Здесь происходит последовательная связь состояний в соответствии с работой бинарной итерации в граф-схеме:

procedure TRE_Iteration.buildMinimizationTable(var table:TMinimizationTable; minRec:TMinRecord); var

finish: TState; begin

finish := minRec.finish; minRec.finish := table.createState(); table.linkStates(minRec.finish, finish, Minimization.EmptySymbol);

m_Leftpperand.buildMinimizationTable(table, minRec);

//

finish := minRec.finish; minRec.finish := minRec.start; minRec.start := finish;

m_Rightpperand.buildMinimizationTable(table, minRec); end;

Рис. 9. Пример вызова процедуры минимизации для операции итерации

Реализация buildMinimizationTable для TRE Leaf (терминального символа). Здесь стартовое и конечное состояния связываются направленной дугой с пометкой символом нетерминала (пример на рисунке 10).

procedure TRE_Leaf.buildMinimizationTable (var table:TMinimizationTable; minRec:TMinRecord); var

a: string; begin

a := getstring;

table.linkStates(minRec.start, minRec.finish, a); end;

Рис. 10. Пример процедуры минимизации для терминальной вершины

Заключение

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

Алгоритм минимизации регулярных выражений КСР-грамматики, реализованный в системе SynGT следующий:

- для каждого регулярного выражения в правых частях правил грамматики строится его граф-схема;

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

- детерминированный конечный автомат, полученный на предыдущем шаге, минимизируется по известному алгоритму [1];

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

- эту процедуру повторяем для всех правил грамматики.

Алгоритмы построения минимизированных по числу вхождений символов и числу состояний детерминированного конечного автомата для произвольной контекстно-свободной грамматики в регулярной форме реализованы в системе эквивалентных преобразований SynGT [2, 3].

Литература

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

2. Федорченко Л.Н. Регуляризация контекстно-свободных грамматик на основе эквивалентных преобразований синтаксических граф-схем. // Труды СПИИРАН. - 2010. - Вып.4(15). - С. 213-230.

3. Федорченко Л.Н. Регуляризация контекстно-свободных грамматик. / LAP LAMBERT Academic Publishing GmbH & Co. KG Dudweiler Landstr. 99, 66123 Saarbrucken, Germany. - 2011. - С 180.

4. Федорченко Л.Н. Синтаксически управляемая обработка данных для практических задач // Вестник БГУ. - 2013. - № 9. - С. 87-99.

Федорченко Людмила Николаевна, кандидат технических наук, старший научный сотрудник лаборатории прикладной информатики Санкт-Петербургского института информатики и автоматизации РАН (СПИИРАН). Тел. +7 (812) 328-1919, e-mail: LNF@iias.spb.su

Fedorchenko Lyudmila Nikolaevna, candidate of technical sciences, senior researcher, St.Petersburg Institute for Informatics and Automation of the Russian Academy of Sciences (SPIIRAS).