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

УДК 681.51

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

СИНТАКСИЧЕСКИ УПРАВЛЯЕМАЯ ОБРАБОТКА ДАННЫХ ДЛЯ ПРАКТИЧЕСКИХ ЗАДАЧ

В статье рассматриваются различные определения синтаксиса и семантики КС-языка на основе атрибутного подхода. Сравнивается синтаксическое описание атрибутов в VW и аффиксных грамматиках Костера (affix grammars) для задания трансляций. Представлен метод описания синтаксиса КС-языка с помощью синтаксической граф-схемы (СГС), построенной по регулярным выражениям. Показан принцип регуляризации грамматики для её приведения в более простой класс грамматик с помощью эквивалентных преобразований СГС. Дан алгоритм одного эквивалентного преобразования КС-грамматики в регулярной форме.

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

© L.N. Fedorchenko SYNTAX-DRIVEN DATA PROCESSING FOR PRACTICE

The article is devoted to the different definitions of syntax and semantics of programming languages on the basis of attribute approach. The syntactic description of attributes in VW and Koster affix grammars are compared for tasks of translations. The method of syntax definition of CS language is presented by means of the syntactic graph-scheme (SGS) constructed on regular expressions. To optimize a parser into simpler class of grammar the principle of grammar regularization has been shown, it uses the SGS equivalent transformations. The algorithm of one of equivalent transformations for the CS-grammar in a regular form has been given.

Keywords: equivalent transformations of grammar, affix grammar, CSR grammar, attribute approach, static semantics.

Введение

При построении синтаксического анализатора как составной части транслятора необходимо проводить эквивалентные преобразования грамматики реализуемого языка. Сейчас языковые технологии активно включаются в различные сферы нашей жизни, что привело к развитию современных транслирующих систем, ориентированных на разнообразный ассортимент вычислительных устройств во многих предметных областях. При этом проявилась проблема быстрой настройки (преобразования) синтаксического определения языка на ту форму, которая допускает автоматическую или ручную реализацию, а также проблема учёта ограничений выбранного метода синтаксического анализа. Первая проблема обусловлена разнообразием спецификаций реализуемых языков, диапазон которых простирается от обычной формы Бэкуса-Наура (БНФ) и языка разметки HTML до двухуровневых и других видов грамматик. Вторая - ведёт либо к языковой неоднозначности, либо к недетерминированности распознающего автомата. Решение этих проблем связано с корректным отображением транслируемого языка во внутреннее машинное представление. Для этого следует эффективно использовать информацию о языке, определяя его синтаксис и статическую семантику специальной КС грамматикой (трансляционной), которая помимо основной своей функции порождения цепочек языка позволяет задавать трансляции, необходимые разработчикам.

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

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

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

Формальный язык называется языком типа X (по иерархии Хомского), если существует хотя бы одна грамматика данного типа, которая порождает данный язык. Реализаторы языка стремятся выделить составляющую, определяющую язык, с помощью такой грамматики типа Y , которая наиболее проста для обработки, и таким образом перевести реализуемый язык из класса языков типа X в класс языков типа Y , для которого уже существуют отработанные алгоритмы и изученные свойства, например, из класса КС-языков в класс регулярных языков. Теоретики языков, наоборот, стремятся описать язык более выразительными и мощными формализмами, стремясь вместить в формализацию как можно больше свойств языка, например, формализовать семантику, в частности статическую, которую в отличие от динамической семантики можно обработать на фазе синтаксического анализа.

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

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

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

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

Оставляя за рамками статьи споры о терминологии, будем считать, что КС-грамматика, определяющая тексты языка, называется синтаксисом, некоторые правила, относящиеся к правильному использованию слов языка, - статической семантикой, тогда как под динамической семантикой понимается то, каким образом может быть установлено input/output отображение, создаваемое программой в процессе исполнения.

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

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

С теоретической точки зрения к настоящему времени создано несколько абстрактных формализмов для описания языков. Работа по созданию таких формализмов велась в трех направлениях:

1) замена формализма КС-грамматики на более мощную грамматику (с целью формального определения статической семантики языка);

2) встраивание атрибутов и предикатов (проверок) в правила КС-грамматики.

3) введение и пошаговая модификация декларативного состояния преобразователя, построенного по грамматике.

В первом направлении было сделано несколько безуспешных попыток до того момента, как была придумана грамматика ван Вейнгаардена (VW), которая использовалась в определении языка ALGOL 68. Отдельные семантические свойства языка были описаны и включены в «Сообщение о языке ALGOL 68» [7].

Во втором направлении важной работой стала статья Д. Кнута (D. Knuth) [9], суть которой заключается в том, что каждая синтаксическая конструкция имеет наследуемые и синтезированные атрибуты. Затем появилась аффиксная грамматика Костера [8], в которой идея с атрибутами Кнута получила дальнейшее развитие. Работы Костера по аффиксным грамматикам стали теоретической основой при определении языка CDL(Compiler Definition Language). К этому направлению относятся и многочисленные функциональные грамматики. Помимо Кнута похожий метод значительно позже был предложен Гриффитсом (M.Griffits) [12].

Третье направление, которое основывается на работе Ледгарда (H.F.Ledgard)[10], было реализовано в работах Вильямса (M.H.Williams)[11] и других авторов. В этом случае имеется таблица (или что-то подобное ей), содержащая текущие имена с текущими атрибутами, и есть множество функций, которые связаны с синтаксическими конструкциями для модификации состояния таблицы. В таком методе терминальные символы КС-грамматики имеют функции перехода из состояния в состояние. Атрибуты для синтаксических единиц более высокого уровня вводятся так же, как в грамматике (VW) ван Вейнгаардена [7,16]. Такой метод дает более ясное разделение между синтаксисом и статической семантикой. Ниже приводится пример применения данного метода для фрагмента реального языка.

2. Грамматика ван Вейнгаардена (VW) и порождаемый ею язык

Грамматику ван Вейнгаардена можно рассматривать как КС-грамматику с бесконечным числом порождающих правил. Это бесконечное множество правил задаётся конструктивно. Символы грамматики обозначаются длинными буквенными строками и называются протопонятиями. Терминальные символы заканчиваются словом “-symbol”. Все символы грамматики отделяются друг от друга запятыми.

Для построения порождающих правил КС-грамматики даны схемы. Это так называемые гиперправила, левые и правые части которых состоят из понятий (символов грамматики), составленных из прописных слов (протопонятий) и из слов заглавного алфавита (метапонятий). Эти метапонятия являются параметрами гиперправила.

Для каждого метапонятия дана КС-грамматика, порождающая, возможно, бесконечное множество протопонятий.

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

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

Используя метапонятия, мы можем генерировать порождающие правила алгоритмом типа Маркова. Некоторые символы в гиперправилах играют особую роль, а именно: из них можно вывести пустую строку. Такие символы грамматики называются предикатами. Они могут выразить отношение между параметрами-метапонятиями. Если такое отношение имеет значение «истина», значит, мы можем вывести пустую строку. Если отношение ложно, вывод останавливается и нетерминальный символ остаётся в текущей полувыведенной строке. В этом случае такой вывод считается неверным, а ветка вывода - тупиковой.

Метаправила: 'ALPHA' : A; В; X; Y; Z.

'LETTER': letter 'ALPHA'.

'NAME': 'LETTER'; 'LETTER' NAME'.

'DEF': 'NAME' has 'MODE'.

'TABLE': 'DEF'; 'TABLE' 'DEF'.

'DEFSETY': 'TABLE'; 'EMPTY'.

'EMPTY' : .

Гиперправила:

Program:

Begin symbol, Declare of 'TABLE', 'TABLE'

restrictions,

'TABLE' statement train, end symbol.

'DEFSETY' 'NAME' has 'MODE' restrictions:

where 'NAME' is not in 'DEFSETY',

'DEFSETY' restrictions;

where 'DEFSETY' is 'EMPTY'.

Where 'NAME 1' is not in "NAME2' has 'MODE' 'DEFSETY':

where 'NAME1' differs from 'NAME2',

where 'NAME1' is not in 'DEFSETY';

where 'NAME1' differs from 'NAME2',

where 'DEFSETY' is 'EMPTY'.

Where 'EMPTY' is 'EMPTY':

'EMPTY'.

Where 'NAME1' letter 'ALPHA1'differs from 'NAME2' letter

'ALPHA2':

where 'NAME1' differs from 'NAME2';

'ALPHA1 is not 'ALPHA2'.

Where 'NAME' letter 'ALPHA1' differs from letter 'ALPHA2'

'EMPTY'.

Where letter 'ALPHA1' differs from 'NAME' letter 'ALPHA2'

'EMPTY'.

A is not B: 'EMPTY'.

A is not C: 'EMPTY'.

A is not D: 'EMPTY'.

и т.д.

Рис.1. Пример 1 грамматики ван Вейнгаардена

Примечание. Двухуровневые грамматики более выразительны, чем грамматики типа 0 по иерархии Хомского. При некоторых допущениях двухуровневые грамматики могут порождать языки с неограниченным набором терминальных символов. Грамматики типа 0 не могут. Доказательство этого факта можно найти в работах Дика Груне (Dick Grune) [14, 15, 17].

В примере 1 покажем фрагмент двухуровневой грамматики, с помощью которой можно проверить свойство, что каждая переменная в программе объявлена только один раз. (Заметим, что альтернативы в правилах разделяются точкой с запятой, левая и правая части КС-правила - двоеточием, правило заканчивается точкой).

В этом фрагменте 'TABLE' restrictions является предикатом, который проверяет единственность описания. Из примера видно, что такой тип определения является понятным и исчерпывающим. С другой стороны, мы можем видеть, что такое определение является скорее избыточным, не математическим, но на практике реализуемым, поскольку используются очень простые функции и трюки.

3. Аффиксные грамматики и язык описания компилятора CDL

Другое решение было предложено Д. Кнутом (D.E. Knuth). Оно состояло в том, что каждая грамматическая единица в КС-грамматике (каждый грамматический символ) имеет набор атрибутов. Атрибут называется «восходящим» или синтезируемым (ascendent), если он выведен из атрибутов грамматических единиц более низкого уровня. Атрибут называется «наследуемым» (descendent), если он выведен из атрибутов грамматической единицы более высокого уровня.

Такая концепция вместе с концепцией VW грамматики породили концепцию аффиксной грамматики, где рассматривается 3 типа объектов. Нетерминальные символы обозначают грамматические единицы, терминальные символы, которые являются словами программы

и связаны с грамматическими объектами. Атрибут может иметь символьное или константное значение.

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

Пример 2. Ниже приводим пример аффиксной грамматики, аналогичный грамматике VW из предыдущего примера 1, однако детально рассмотрим иную часть вывода.

Program: Begin,

Declaration+'TABLE ' ,

Restrictions+'TABLE',.

Statement train+'TABLE',

End.

Declaration+'TABLE': Declare+'MODE'+'TABLE';

Declare+'MODE'+'SUBTABLE1',

Declaration+'SUBTABLE2',

Union+ ' TABLE ' + ' SUBTABLE1' + ' SUBTABLE2 ' .

Declare+'MODE'+'TABLE': Declare+'MODE',

Idlist+'TABLE'+'MODE'.

Idlist+'TABLE'+'MODE': Identifier+'NAME',

Include+'TABLE'+'NAME'+'MODE',Semicolon symbol;; Identifier+'NAME',

Include+'TABLE'+'NAME'+'MODE',Comma symbol, Idlist+'TABLE'+'MODE'.

Рис. 2. Пример аффиксной грамматики

В примере 2 ограничения Restrictions являются предикатом над областью таблиц 'TABLE', который проверяет единственность имени в таблицах. Предикат объединение 'Union' проверяет, что таблица 'TABLE' является объединением двух подтаблиц 'SUBTABLE'. Предикат Include проверяет наличие имени 'NAME' типа 'MODE' в таблице 'TABLE'.

Наиболее известным в применении аффиксных грамматик стал язык CDL (Compiler Description Language), созданный Костером (Cornelis H. A. Koster) в университете Nijmegen.

В первоначальной редакции CDL - это аффиксная грамматика, слегка модифицированная. “CDL-программа” является синтактико-семантическим определением, которое транслируется в код, выполняющий синтаксический анализ программы. Трансляция CDL-программы организована так, что нетерминальные символы (грамматические понятия) транслируются в рекурсивные процедуры, а терминальные символы и предикаты - в макросы, которые должен писать (разрабатывать) сам пользователь (разработчик транслятора исходного языка). Телом каждой такой процедуры является последовательность вызовов процедур и макросов в соответствии со структурой объектов аффиксного правила. Синтаксический разбор идёт по типу «сверху-вниз» и «слева-направо». Поэтому в CDL леворекурсивные правила исключаются.

Примечание. Расширить класс аффиксных грамматик, используемых в CDL или других системах подобного рода можно за счёт эквивалентного преобразования, исключающего леворекурсивные правила из грамматики [18-19, 27, 30-32], при котором синтактико-семантическое значение грамматических конструкций языка остаётся прежним (каким оно планировалось до преобразования).

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

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

Из примеров 1, 2 видно, что некоторые семантические свойства языков программирования можно задавать с помощью атрибутов как в грамматиках VW, так и в аффиксных грамматиках, используя

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

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

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

3. Метод переходных состояний

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

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

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

Иной подход был предложен Ледгардом (H.F.Ledgard), который был использован для определения статической семантики в PL/1. В этой модели атрибуты не включаются в контекстно-свободную грамматику. Они встраиваются в синтезированные по грамматике синтаксические таблицы. По мере продвижения по тексту программы состояние такой таблицы меняется на каждом шаге перехода. Модификация состояния выполняется тогда, когда завершается распознавание синтаксической конструкции, то есть продукционное правило грамматики, определяющее данную конструкцию, завершено. В этом случае соответствующее состояние в таблице переходов выполняется и включается модифицирующая и проверяющая функции, связанные с этим правилом. Такую модель M.H.Williams назвал диахронной (в отличие от предыдущих синхронных моделей).

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

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

-возможность автоматической генерации транслятора;

-возможность автоматического анализа свойств транслируемого (входного) языка;

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

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

4. О регуляризации контекстно-свободных грамматик

Термин «регуляризация» для грамматик отличен от общепринятого понятия регуляризации функций в математике. Под регуляризацией контекстно-свободной грамматики (КСГ) понимается опреде-

92

лённая схема её эквивалентных преобразований с целью определения языка с помощью регулярных множеств слов, порождаемых данной грамматикой. В этом случае достигается максимальная эффективность синтезируемого распознавателя (анализатора) языка, а исходная грамматика может быть переведена в класс регулярных грамматик. В результате регуляризации получают КСГ в регулярной форме (КСР-грамматику) [18, 21, 29-33], эквивалентную исходной грамматике. Это означает, что языки, порождаемые исходной и преобразованной грамматиками, совпадают. Правила КСР -грамматики определяют терминальные порождения нетерминалов через регулярные выражения относительно символов всех алфавитов грамматики. В этом случае соответствующий языковой процессор подобен множеству конечных автоматов, каждый из которых распознает свой фрагмент входной цепочки языка. В процессе преобразований из правил грамматики исключаются разного рода рекурсии (лево и правосторонние), с помощью подстановок удаляются вхождения нетерминалов (где это возможно) и непродуктивные правила. Количество правил КСР -грамматики резко уменьшается, а их правые части представляют собой сложные регулярные выражения. Часть таких преобразований реализована в программной системе SynGT (Syntax Graph Transformations) [27-30]. В конце статьи приводится алгоритм исключения одновременно и лево-, и праворекурсивных нетерминалов из КСР -грамматики, регулярные выражения которой содержат операцию обобщенной итерации.

Регулярным выражениям (РВ) как мощному средству обработки текстов посвящено огромное количество исследований. РВ поддерживаются многими редакторами, утилитами, системами построения трансляторов и обработки данных. Они занимают центральное место во многих программах, написанных на языках Java, Jscript, Visual Basic, VBScript, Java Script, C, C++, C#, Perl, Python Tcl, Ruby, Awk и других. Поддержка РВ в столь разнородных приложениях объясняется тем, что они обладают исключительно богатыми возможностями.

Регулярное выражение - это абстракция, которая по-разному реализуется в различных программах. Термин «регулярные выражения» заимствован из формальной алгебры. Истоком регулярных выражений явилась работа двух нейрофизиологов - Уоррена Мак-Каллох (Warren McCulloch) и Уолтера Питтса (Walter Pitts), которые занимались моделированием деятельности нервной системы. Их статья “A logical calculus of the ideas immanent in nervous activity” была впервые опубликована в биологическом бюллетене в 1943 году, а позднее перепечатана MIT Press в 1965 г. Через несколько лет математик Стивен Клини (Stephen Kleene) формально описал эти модели на языке алгебры, которую он назвал алгеброй регулярных множеств (regular sets) [4]. Для них он разработал простую математическую запись, которую назвал регулярными выражениями.

Они строятся из элементарных выражений, которые просты, но в сочетании друг с другом образуют бесконечное множество комбинаций. В разных программах регулярные выражения выполняют различные функции, поэтому наборы метасимволов и другие возможности, поддерживаемые программами, также различаются. Совокупность этих второстепенных различий в реализации обозначают обычно термином “диалект”. В конце 1990-х годов диалект регулярных выражений языка Perl прославился особой мощью и выразительностью. Появились другие примеры диалектов регулярных выражений в таких языках, как Python, пакеты FB для Java, Microsoft.NET Framework, Tcl, различные библиотеки языка Си и т.д. Диалекты развивались, в итоге общая ситуация становилась все более разнообразной.

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

Далее напомним определения регулярного множества и регулярного выражения и дадим их по Клини [5], обобщения которых были введены и подробно обоснованы в [1-3].

Пусть дан алфавит символов V — {al,a2,...,an} . V* - множество всех слов в алфавите V .

Определение 1. Регулярным множеством слов (регулярным языком) над алфавитом V называют следующие множества:

1) {в} - (пустое слово);

2) 0 - (пустое множество слов);

3) {а; } - элементарные множества слов над алфавитом V для любого «, е V:

4) множества P и Q , PQ, P* где Р и Q - регулярные множества в алфавите V .

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

В работах [1-3] вводится бинарная операция обобщенной итерации (#) над множествами слов в алфавите V . Иногда её называют итерацией с разделителем [2].

Если первый или второй операнд обобщенной итерации представляет собой множество в = {в} и, если позволяет однозначность представления, то он может быть опущен. Пусть Л - регулярное множество слов, тогда справедливы следующие равенства: Л# = Л# в = ЛЛ* = Л+, # Л = в# Л = Л *.

Для представления регулярного множества Клини в [4] ввел понятие регулярного выражения в алфавите V . Дадим определение регулярного выражения для случая введенных операций над множествами слов.

Определение 2. Регулярным выражением множества Л называется слово г(Л) над расширенным алфавитом W, где

W = V и {#,*,+ ,|,(,), в, 0},

причем:

1. если Л = 0, то г( Л) = 0;

2. если Л = в, то г(Л) = е ;

3. если Л = {а}, где а е V , то г (Л) = а ;

4. если г(Р) = р и г^) = q - регулярные выражения для множеств Р и Q то: а г(Л) = (р | д), для множества Р и Q ;

Ь г(Л) = (pq), для множества PQ ; с г (Л) = (р*), для множества Р *;

d г (Л) = (р+), для множества Р+ ;

е г(Л) = (р# q), для множества Р# Q

Ничто другое не является регулярным выражением.

Эти определения аналогичны определениям из [6] и являются общепринятыми. Операция усеченной итерации (р+) обозначает (р(р *)), а операция итерации с разделителем (р# д) обозначает р((др) *). Введем операции {;} и {,} для объединения и конкатенации. Кроме этого, будем удалять из выражений лишние скобки. Для этого опишем приоритеты операций:

1) унарные операции {*} и {+} обладают наивысшим приоритетом,

2) затем идет итерация с разделителем или обобщенная итерация {#} ,

3) затем конкатенация {,},

4) и далее объединение {;} .

Так, регулярное выражение р*; д,р#д с учетом приоритетов означает ((р*);(д(р# д))).

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

В литературе для определения синтаксиса языка в виде правил грамматики с регулярными правыми частями обычно используется нотация, называемая расширенной формой Бэкуса-Наура (EBNF),

где используются операции Клини - обычная {*} и усеченная {+} (см. определение языка Паскаль, Ада, С и другие). В этой статье мы используем определение КСР- грамматики, в которой в регуляр-

ных выражениях присутствует как обобщенная операция итерации {#} (по Г.С. Цейтину), так и операции Клини.

Следуя общепринятой терминологии [5,6], грамматики, содержащие правила вида (А, г) , называются КС-грамматиками в регулярной форме. Каждое правило такой грамматики может интерпретироваться как множество правил вида {А —> х \ х е Л(г): Л(г) — регулярный язык над алфавитом V},

где V — объединение алфавитов (словарей) терминальных и нетерминальных символов, V = N и Т .

Опыт применения грамматик данного класса диктует дополнить определение грамматики [5] как четверки множеств С = (Ы, Т, Р, £) множеством семантик, служащих для вставки необходимых обрабатывающих кодов в компилируемый по данной грамматике текст. Таким образом дадим определение КСР-грамматики, как ее понимаем в системе 8упСТ.

Определение 3. КСР-грамматикой называется пятерка множеств Ск — (Ы,Т,Ъ,Р,8), где N - множество нетерминалов, Т - множество терминалов, X - множество семантик, Р - множество КСР-правил, Р = {А: КА. \ А € Ы,КА - регулярное выражение над алфавитом N и Т и 1}. .V - начальный нетерминал грамматики.

5. Преобразования КСР-грамматики

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

Рассмотрим преобразования регулярных выражений, не изменяющие регулярное множество, которые реализованы в SynGT. Большинство из них описано в монографии Ахо и Ульман [5] и называются регулярными тождествами. Существуют и нетривиальные тождества, например, (.А#(В#С)) = А,(е;В#(А;С),А).

Каждое правило в КСР грамматике записывается в следующей форме:

<нетерминал>:<регулярное выражение>.

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

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

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

Дадим формальное определение крайней рекурсии в КСР-грамматике так, как оно дается в [5].

Определение 4. Нетерминал А называется самовложенным, если в грамматике существует вывод

*

вида А => аЛр, где а, Р - непустые строки в алфавите нетерминалов, терминалов и семантик.

Иными словами, нетерминал А является самовложенным, если он выводим сам из себя с непустым левым и правым контекстом. В работе такой нетерминал ещё называют «самовставленным» (self embedded [5, 6]).

Определение 5. Нетерминал А называется леворекурсивным, если существует вывод А => *А[:>, где /3 - непустая строка в алфавите нетерминалов, терминалов и семантик.

Определение 6. Нетерминал А называется праворекурсивным, если существует вывод А => *схА , где а -непустая строка в алфавите нетерминалов, терминалов и семантик.

Легко показать, что если A не является самовложенным нетерминалом, то он не может быть одновременно лево- и праворекурсивным. Иначе мы могли бы построить вывод А=>*аАД Из теории формальных грамматик [5, 6] известно, что язык регулярен, если любая грамматика, которая его порождает, не содержит самовложенных нетерминалов. Любой регулярный язык распознается конечным автоматом. В этом случае существует регулярное выражение над алфавитом терминалов, представляющее тот же самый язык. Оно может быть получено с помощью эквивалентных преобразований над КСР-правилами. Если при преобразовании достигается цель минимизации этого регулярного выражения (относительно числа вхождений символов алфавита грамматики), то и распознающий автомат по данному выражению будет минимальным.

Подобные преобразования выполняются в системе эквивалентных преобразований КСР-грамматики SynGT. Рассмотрим алгоритм исключения (лево/право) рекурсивных нетерминалов в КСР-грамматике G без самовложений для случая, когда регулярное выражение в правиле для рекурсивного нетерминала содержит обобщенную итерацию. Заметим, что в работах [1,3,5] этот случай не рассматривался.

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

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

Рассмотрим A -правило для нетерминала A вида

A: A, rn, A; A, r12;r21, A; r22.,

где /j 1, r12, r21, г22 ~ регулярные выражения над алфавитом N <JT иЕ}.

Данное А -правило (1) состоит из четырёх частей (Д -фрагментов), / = 1,2,3,4:

А, r11,А ; А, r12 ; r21,А ’ r22 >

где

А1 -фрагмент содержит одновременно и лево, и праворекурсивное вхождение нетерминала А ;

А2 -фрагмент содержит левоорекурсивное вхождение нетерминала А ;

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

А4 -фрагмент не содержит рекурсивных вхождений нетерминала А .

Рассмотрим, какие строки могут порождаться с помощью А -правила (1).

Шаг 1. Рассмотрим А1-фрагмент А -правила: А, r11, А . Используя данный фрагмент А -правила, мы можем вывести строки

А, Аг11 А, Аг11 Аг11 А,... ,

Из определения операции # это множество строк совпадает с множеством строк, порождаемым регулярным выражением

А# гц .

Шаг 2. Рассмотрим А2 - фрагмент A - правила: А, . Здесь мы можем вывести строки

А r12, Аг 12 r12, Аг12 r12 r12, ••• .

Из определения операции * следует, что множество (2.1) порождается регулярным выражением

А,r12 * .

Подставив вместо А в выражении (2) А2 -фрагмент А -правила (2.2), получим регулярное выражение

Шаг 3. Аналогично для праворекурсивного вхождения нетерминала А в А3 -фрагменте. Здесь мы выводим множество строк 7*21 А, r21r21A, r2\r2\r2\А, •••, которые порождаются регулярным выражением Г21*, А . Сделав подстановку вместо вхождения нетерминала А в (3) выражения т^*, А , получим регулярное выражение

Шаг 4. Окончательно, подставляя вместо вхождения нетерминала А в регулярное выражение (4) А4 - фрагмент r22, получим эквивалентное регулярное выражение

Таким образом, правую часть А — правила (1) можно заменить регулярным выражением (5).

Если предварительно воспользоваться преобразованиями регулярных выражений и привести правило к такому виду, что множество L(ru) не содержит цепочек вида аА, множество L(r2l) не содержит цепочек вида А а , а множество Ь(г22) не содержит цепочек вида А и. и вида аА, где а про-

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

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

Если r11, r12, r21, r22 - регулярные выражения, не содержащие вхождений нетерминала А, то нетерминал А и правило для него можно удалить из грамматики G', а все его вхождения заменить выражением (r21*, r22, r12*)#r11.

Заключение

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

Литература

1. Федорченко Л.Н. Об алгоритме синтаксического анализа детерминированных языков // Computer Networks Leningrad Computing Center of the Academy of Sciences and Computer and Automation Institute of Hungarian Academy of Sciences: материалы совместного с Венгерской академией наук семинара.- Budapest, 1978.- C.73-78.

2. Федорченко Л.Н. Об одном алгоритме синтаксического анализа языков, порождаемых R-грамматиками // Алгоритмы и системы автоматизации исследований и проектирования: сб. науч. тр. / ЛНИВЦ АН СССР. - М.: Наука, 1980. - C. 146-155.

3. Федорченко Л.Н., Мартыненко Б.К. Эквивалентные преобразования КСР грамматик в регулярной форме в практике построения языковых процессоров. Ч. 1. Определение и распознавание КСР-языков посредством синтаксических граф-схем. - Л., 1983. - C. 55.

4. Клини С. Представление событий в нервных сетях // Автоматы. - М.:ИЛ,1956. - С. 15-67.

5. Ахо А., Ульман Дж. Теория синтаксического анализа, перевода и компиляции. - М.: Мир, 1978.

- Т.1. Синтаксический анализ. 612 с.; Т.2. Компиляция. 487 с.

6. Ginsburg S. The mathematical theory of ^^ext-free languages. Mc Graw-Hill Inc., 1966.

7. Revised report on the algorithmic language Algol 68 // ACTA Informatica 5. Пересмотренное сообщение о языке ALGOL 68. - 1974. - P. 1-236.

8. Koster Affix grammars // Algol 68 implementation. - Noth-Holland, 1971.

9. Knuth D.E. Semantics of context-free languages // Mathematical system theory. - 1968 (2). - P. 127-145.

10. Ledgard H.F. Production system or can we do better than BNF? // CACM. - 1974, N2. - P. 94-102.

11. Williams V.H. Static semantics features of Algol 60, and BASIC // The Computer Journal. - Vol. 21, №. 3. - P. 234-242.

12. Griffiths M. Relationship between definition and implementation of language // Advanced courses on software engineering. Lecture Notes in Economics and Math Syst. Springer-Verlag 1973.

13. Bochmann G.V. Semantic evaluation from left to right // CACM. - 1976, №2. - P. 55-62.

14. Grune Dick. Two Level grammars are more expressive than Type 0 grammars or are they? // Dept. of Mathematics and Computer Science Vrije Universiteit, De Boelelaan 1081, HV Amsterdam. dick@cs.vu.nl

15. Sintzoff M. Existence of a van Wijngaarden syntax for every recursively enumerable set // Annales de la Societe Scientifique de Bruxelles. - 1967. № 81(II). - P. 115-118.

16. van Wijngaarden A. The generative power of two-level grammars // Automata, Languages and Programming: Lecture Notes in Computer Science #14, ed. J. Loecks. Springer-Verlag. - Berlin, 1974. -P. 9-16.

17. Grune Dick, Jacobs Ceriel. Parsing Techniques. A Practical Guide // Ellis Horwood, Chichester, 1990. - P. 322.

18. Федорченко Л.Н. О регуляризации контекстно-свободных грамматик // Изв. вузов. Приборостроение. - 2006. - Т. 49, №11. - C. 50-54.

19. Федорченко Л.Н., Заболотский В.П. Лингвистический инструментарий в задачах обеспечения информационной безопасности // Проблемы информационной безопасности. Компьютерные системы. - 2008. - Вып. 4. - С.60-68.

20. Федорченко Л.Н. О числе состояний распознавателя, порождаемого с помощью КС-грамматик в регулярной форме // Информационные и вычислительные проблемы в научных исследованиях: сб. науч. тр. - M.: Наука, 1983. - C. 69-73.

21. Инструментальная система для решения задач планирования и оптимизации вычислений в распределенной среде на основе графовых трансформаций / Л.Н. Федорченко и др. - М., 1998. - 70 с.

22. Федорченко Л.Н., Баранов С.Н., Кутузов М. Грамматика языка Си // OCC - открытый компилятор языка Си. - М., 1998. - С. 5.

23. Усовершенствованный алгоритм экранного размещения синтаксической граф-схемы в системе SynGT (Syntax Graph Transformation) версии 3.1. / Л.Н. Федорченко и др. // OCC - открытый компилятор языка Си для цифровых сигнальных процессоров. - М., 1999. - С. 45-46.

24. Средства визуализации синтаксических граф-схем - СПИИРАН / Федорченко Л.Н. и др. // Региональная информатика-98 (РИ-98): материалы VI Междунар. конф., Санкт-Петербург, 2-4 июня 1998. - СПб., 1999. - C. 55-56.

25. Федорченко Л.Н. Специализированный редактор для обработки контекстно-свободных грамматик в регулярной форме. - СПИИРАН, тр. VI Междунар. конф. «Региональная информатика-98» (RI-98), СПб., 1999. - C. 56-57.

26. Федорченко Л.Н. Извлечение крайней рекурсии из КСР грамматики в системе SynGT. // Тр. СПИИРАН. - Вып.1. - Т.1. - СПб.: СПИИРАН, 2002. - С. 350-359.

27. Федорченко Л.Н., Соловьев С.В. Синтаксические преобразования в системе SynGT и их новые приложения // Региональная информатика-2002 (РИ-2002): материалы VIII Междунар. конф. в 2 ч., Санкт-Петербург, 26 - 28 ноября 2002 г. 2002. - С. 50.

28. Федорченко Л.Н., Маньков Е.В. Современное состояние и классификация систем построения компиляторов // Региональная информатика-2004 (РИ-2004): материалы IX Междунар. конф. (Санкт-Петербург, 22-24 июня 2004 г.). 2004. - С. 66.

29. Fedorchenko L., Naumov I. Syntax Graph Transformations in The System SynGT and Their New Applications, Procs of 10-th Multi-conference on Advanced Computer Systems (ACS-AIBITS 2003), October 22-24, Poland.

30. Fedorchenko L. Syntax Graph Transformations in the System SynGT and Regularization of Grammars, Procs of Intern Multi-Conference on Advanced Computer Systems (ACS-CISIM 2004), 14-16 June, Elk, Poland [электронный ресурс] http://acs.wi.ps.pl/info.php

31. Федорченко Л.Н. Метод регуляризации грамматик в системах трансляции языков // Инновации в науке и образовании-2008: материалы VI Юбил. междунар. науч. конф., посвящ. 50-летию пребывания КГТУ на Калининградской земле: в 3 ч. - Калининград, 2008. - Ч. 2.- С. 305.

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

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

34. Лукьянова Л.М., Федорченко Л.Н. Средства формализации целей и проблем сложных систем производственной сферы // Вестн. БГУ. - 2012. - № 9. - С. 42-48.

35. Лукьянова Л.М., Федорченко Л.Н. Формализация систем целей в производственной сфере // Региональная информатика-2012: материалы XIII Междунар. конф. (Санкт-Петербург, 24-26 октября 2012 г.). - 2012. - С. 172-173.

36. Atiskov A., Fedorchenko L., Moldovyan N., Novikov F., Vorobiev V. Ontology-Based Analysis of Cryptography Standards and Capabilities for Their Harmonization. // Theory and Practice of Cryptography Solutions for Secure Information Systems // IGI Global, 701 E. Chocolate Ave. Hershey, PA 17033, USA. 2013.

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

Fedorchenko Lyudmila Nikolaevna, senior researcher, candidate of technical sciences, St.Petersburg Institute for Informatics and Automation of the Russian Academy of Sciences (SPIIRAS). Ph. +7 (812) 3281919. E-mail: LNF@iias.spb.su