Научная статья на тему 'Челночные трансляции в SYNTAX-технологии'

Челночные трансляции в SYNTAX-технологии Текст научной статьи по специальности «Математика»

CC BY
100
14
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
ГРАММАТИКИ / СИНТАКСИЧЕСКИЕ ДИАГРАММЫ Н. ВИРТА / ГРАФ-СХЕМЫ / ТРАНСЛЯЦИИ / GRAMMARS / N. WIRTH'S SYNTACTIC FLOWCHARTS / GRAPH-SCHEMES / REGULAR SPLINES / TRANSLATIONS

Аннотация научной статьи по математике, автор научной работы — Мартыненко Борис Константинович

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

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

Shuttle translations in the SYNTAX-technology

The method of creation contextually dependent spline shuttle processors used in SYNTAX-technology for implementation of syntactically controlled translations is described. The method is based on RBNF-grammars, represented in a form of modified N. Wirth’s charts, graph-schemes. The processors possess the linear estimation of complexity on time concerning length of an input sentence.

Текст научной работы на тему «Челночные трансляции в SYNTAX-технологии»

Компьютерные инструменты в образовании, 2014 № 5: 3-15

УДК: 519.682.1 +681.142.2

http://ipo.spb.ru/journal

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

Ключевые слова: грамматики, синтаксические диаграммы Н. Вирта, граф-схемы, трансляции.

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

Разумеется, не всякая КВКБ-грамматика годится для построения адекватного процессора, описанного в [1]. Ограничения, накладываемые на грамматику, диктуются требованием детерминизма управления просмотров челночного процессора. Они проверяются в процессе их построения.

Пусть задана трансляционная граф-схема ^ = (^с, Е), которая, как мы знаем [1], состоит из управляющей граф-схемы (^с) и описания операционной среды (Е).

Пусть ^с= N Т, ЗД, X, К, £), где N — алфавит нетерминалов; Т — алфавит терминалов; ЗД = ЗД* и ЗДЬ (ЗД* о ЗДЬ = 0) — алфавит резольверных символов, состоящий из резольверов прямого (ЗД*) и обратного (ЗДЬ) просмотров; X = X* иХь (X* о Хь = 0) — алфавит семантических символов, состоящий из семантик прямого (X*) и обратного (Хь) просмотров; К — множество компонент управляющей граф-схемы, каждая из которых определяет некоторый нетерминал; £ — начальный нетерминал.

Мартыненко Борис Константинович

Аннотация

ВВЕДЕНИЕ

1. ПОСТРОЕНИЕ ЧЕЛНОЧНЫХ СПЛАЙНОВЫХ ПРОЦЕССОРОВ

© Мартыненко Б.К., 2014

Опишем метод построения челночного сплайнового процессора Р = (Р/, Рсь, Е), где Р/, Р,ь — управляющие процессоры соответственно прямого и обратного просмотров; Е — операционная среда. Поскольку операционная среда компилируется по её описанию (Е), заданному в составе трансляционной граф-схемы, то остается определить, как строить управляющие процессоры прямого и обратного просмотров.

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

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

2. ПОСТРОЕНИЕ УПРАВЛЯЮЩЕГО ПРОЦЕССОРА ПРЯМОГО ПРОСМОТРА

Вход: % = (N, T, ЭТ, A, K, S) — управляющая граф-схема.

Выход: Pcf = (Qf, rf, Af, 5f, qf0 , F) — управляющий процессор прямого просмотра. Метод:

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

Zf := T; # T — алфавит терминалов управляющей граф-схемы % # Af — такой же, как в управляющей граф-схеме2; f := (Vo | Vo e Vertex(%c): (Mark(Vo)="begin-S")};

Qf := (qf0}; rf := 0; := 0; F := 0; # Эти четыре множества в дальнейшем пополняются # Continue := true;

# Главный цикл построения управляющего процессора прямого просмотра состоит из цикла совместного пополнения таблиц 5fx и 5f2 и затем цикла пополнения таблицы 5f3, исполняемых поочередно до тех пор, пока флажок Continue не перейдет в состояние false. Это происходит тогда, когда в результате очередного выполнения этапа пополнения таблицы 5f3 не появляется ни одного нового возвратного состояния. И тогда производится проверка внешней балансировки управляющей граф-схемы. Содержательный смысл этой проверки — обнаружение ситуаций, в которых не ясно, отнести ли текущий входной символ к текущей или к объемлющей конструкции языка. Если такая проверка не обнаруживает ни одной неясной ситуации, то гарантирована детерминированность процессора прямого просмотра относительно альтернативы: использовать верхний символ магазина или нет. #

while Continue

do Continue := false; Continue2 := false; # Пополнение таблиц 5f и 5f2. На этом этапе производится разложение состояний, имеющихся в множестве Qf. По разложению состояния проверяются необходимые условия детерминированности процессора и планируются все его возможные движения в данном состоянии. Появляющиеся при этом новые состояния включаются в множество Qf 3, а новые магазинные символы — в множество rf.

Этап пополнения таблиц 5f и 5f2 заканчивается, когда рассмотрены все состояния из

Qf. #

1 Имеется в виду, что используется по возможности синтаксис языка Алгол 68.

2 Напомним, что А = Аг и Аь, Аг п Аь = 0.

3 Те из них, которые оказываются конечными, пополняют также множество Р1.

for Уд: (q е Qf)

do D := Develope(q); # Разложение состояния q — лес, состоящий из деревьев, корнями которых являются вершины множества q. #

if Height(D) = да 1

then Alarm((мРазложение состояния '', q, " бесконечно!'')) else # Построение непустых движений в состоянии q. #

for У а: (а е Ef& 3 v:(v е Leaves(Z))&Mark(v)=a))

do

# Отбор ветвей разложения D, листья которых помечены входным символом a. # Da := Subforest(D, a);

if D Ф 0

a

then R := 0; # Сброс резольверных входов для символа a. # for У г: ((г e 91**) & (36: ((6 e Branchcs(/)u)) & (Maik*f(6) = r))))

do # Отбор ветвей из Da, метки которых, если в них учитывать только резольверные символы прямого просмотра, образуют r. # Dar :=Selected branches(Da, r); if Не все ветви Da имеют равную длину

then Alаrm(("Нарушена балансировка разложения состояния '', q, " по''

''входному символу '', a," и составному резольверу ", r, "!" )) else # Обеспечена детерминированность уровня конструкции, к которой относится текущий входной символ # с := Forward pass semantics (Dar); if Ambiguous(c)

then Alаrm(("Семантическая неоднозначность '' ''состояния '', q, '' по входному '' ''символу '', a, '' и составному '' ''резольверу '', r, "!'')) else R := R u {r}; # Пополнение резольверных входов для a #

p := Leaves(Dar); # p — переходное состояние из q по входному символу a при условии, что выполняется составной предикат r, то есть если i(r). #

ef := ef u {p};

a := Push down list(Dar); # a — магазинная цепочка. Если она содержит

символы, которых ещё нет в алфавите rf, то Push down list устанавливает флажок Continue2 в состояние true.

#

5f2 (q, a, r) := (p, a, с) fi

fi

od; # Конец цикла определения резольверных входов для a # 5f1 (q, a) := R

fi # Конец определения движения для входного символа a # od; # Конец цикла построения непустых движений в состоянии q # # Построение s-движений в состоянии q. #

Df := (J Subforest(D, "end-A");

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

A е N

# Df — те ветви разложения D, листья которых помечены символами вида "end-A", где A — некоторый нетерминал.

#

if Df * 0

then # Пустые движения существуют (q — подавляемое состояние). # R := 0; # Сброс резольверных входов для символа в. # for V r:(r е е Branches(Z)f)&Mark9if(6)=r))

do # Отбор ветвей Df, метки которых, если в них учитывать только резольверные символы прямого просмотра, образуют цепочку r.

#

Df r := Selected branches(Df r);

if Не все ветви Df имеют равную длину

then А1агт((''Нарушена балансировка разложения состояния '', q,

'' по конечным меткам и составному резольверу ", r "!" )) else с := Forward pass semantics (Df r); if Ambiguous(c)

then А1агш(("Семантическая неоднозначность '' ''состояния '', q, ''по конечным вершинам и " "составному резольверу '', r, "!" )) else

if Mask(q, r) = {S}1

then # q — конечное состояние #

F := Ff u {q} else # q — подавляемое состояние # Continue2 := true

fi;

R := R u {r}; # Пополнение резольверных входов для в # а := Push down list(Df r);

# а — магазинная цепочка. Если она содержит магазинные символы, которых ещё нет в алфавите rf, то Push down list устанавливает флажок Continue2 в состояние true.

#

5f2(q, в, r) := (Sup, а, с)

fi

fi

od; # Конец цикла определения резольверных входов для в. #

f (q, в) := R

fi # Конец определения в-движений в подавляемом состоянии q. #

fi

fi

od; # Конец этапа пополнения таблиц 5f1 и 5f2. # # Пополнение таблицы 5f3.

Этот этап выполняется только при условии, что флажок Continue2 был установлен в состояние true в цикле пополнения таблиц 5f1 и 5f2. Это же случается тогда, когда во время выполнения упомянутого цикла образуется новое подавляемое состояние или новый магазинный символ.

1 Предполагается, что начальный нетерминал S не встречается в правых частях правил грамматики. Во всяком случае, путём простого эквивалентного преобразования грамматики [5], этого легко добиться.

Рассматриваются всевозможные тройки вида (q, X, r), где q — подавляемое состояние, X е rf, r е (^f* u {s}), для которых значение 5f3(q, X, r) не определено, тогда как значение 5f2(q, s, r) определено. Если q иXсопряжены по составному резольверу r (предполагается, что i(r) выполняется, когда r = s), то по ним определяется возвратное состояние s, которое пополняет множество Qf, и затем 5f3(q, X, r) := s.

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

Если во время выполнения этого цикла появляются новые состояния, то после его завершения снова повторяется этап пополнения таблиц 5f1 и 5f2. #

while Continue2 do Continue2 := false; for Vg: (q e Of&Suppressible(^)) do

for VX: (X e Г1) do

for Vr: (re (91f*u {s})) do

if 5f3(q, X, r) = undefined & Conj(q, X, r)

then # q и X сопряжены по составному резольверу r. #

s := {v | (v е X)&(Mark(v) е Mask(q, r))}; 5f3(q, X, r) := s;

if s g Qf

then # s — новое состояние. #

Qf := Qf u {s}; Continue := true

fi

fi

od # r # od # X # od # q #

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

od # Конец цикла пополнения таблицы возвратных состояний. # od; # Конец главного цикла. #

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

Проверка внешней балансировки. # Ok := true;

for \/q: ((q e <9f) &Suppressible(^)) while Ok

do # Проверяется условие внешней балансировки для каждого дерева возвратных состояний, построенного для подавляемого состояния q. # Ok := External balance(Return tree(q)); if -iOk

then Alarm (''Нарушена внешняя балансировка в состоянии '', q) fi od

Если во время исполнения последнего цикла не обнаружено нарушение внешней балансировки1 , то построенная управляющая таблица прямого просмотра 5f является правиль-

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

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

3. ВСПОМОГАТЕЛЬНЫЕ АЛГОРИТМЫ ДЛЯ ПОСТРОЕНИЯ ПРЯМОГО ПРОСМОТРА

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

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

Ambiguous — семантическая неоднозначность. Процедура дает результат true, если множество, заданное её параметром, содержит более одной семантической цепочки. В противном случае её результат — false.

Branches — множество ветвей, составляющих данный лес. Процедура Branches(/), где f— некоторый лес, выдает множество ветвей, его составляющих.

Conj — сопряженность подавляемого состояния с магазинным символом. Считается, что подавляемое состояние q е Qf сопряжено с магазинным символом X е rf при условии r, если в момент обращения процессора прямого просмотра к магазину в состоянии q, когда интерпретация резольверной цепочки r дает true, на его вершине может оказаться символ X.

Функция Conj(q, X, r), где q — подавляемое состояние, X — магазинный символ, r — составной резольвер, определяется следующим образом:

Conj (q, X, r) =f Mask(q, r) с Mark(X)1.

Create edge — образовать ребро. Процедура Create edge(u,v) образует ориентированную дугу от вершины u к вершине v.

Develope — разложение состояния. Разложение состояния q е Qf, являющегося параметром процедуры Develope, выполняется по следующим шагам:

1. Создаются копии вершин, входящих в множество q. Будем считать, что они принадлежат нулевому уровню разложения данного состояния q. Далее эти копии вершин считаются корнями деревьев, построение которых производится при помощи последующих шагов алгоритма.

2. К каждому корню пристраиваются копии дуг управляющей граф-схемы, инцидентных его прообразу, вместе с их концевыми вершинами и контекстными метками (то есть семантическими и резольверными символами), помечающими эти дуги. Будем считать, что множество присоединенных таким образом вершин образует первый уровень разложения состояния q. Далее, level := 1.

3. К каждой вершине уровня level, которая помечена нетерминалом, пристроим копии дуг управляющей граф-схемы, инцидентных начальной вершине компоненты, определяющей этот нетерминал, вместе с концевыми вершинами и контекстными метками, помечающими эти дуги. Вновь присоединенные вершины будем считать относящимися к уровню level + 1 разложения состояния q. Далее, level := level + 1.

Шаг 3 повторяется до тех пор, пока не обнаружится, что на текущем уровне нет ни одной нетерминальной вершины, и тогда алгоритм построения разложения состояния q заканчивается. Если же шаг 3 «зацикливается», разложение состояния q — бесконечно2 .

1 См. определение функций Mask и Mark далее в этом разделе.

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

External balance — проверка внешней балансировки. Процедура External balance проверяет выполнение условия внешней балансировки для дерева возвратных состояний, корень которого задан как её параметр. Это условие состоит в том, что для каждой пары вершин, принадлежащих одной и той же ветви этого дерева и представляющих некоторые состояния q1 и q2, должно быть:

Accept(q1) n Accept(q2) = 0, где Accept(q) d= {a | (a е Ef) & (3r: ((r е ^f*) & (5f2(q, a, r) — определено))} — множество входных символов, допустимых в состоянии q.

Forward pass semantics — семантика леса. Процедура Forward pass semantics(f) определяет множество семантических цепочек прямого просмотра для леса f заданного её параметром. Именно, для каждой ветви леса f определяется цепочка, составленная из семантических символов прямого просмотра, помечающих эту ветвь. Множество всех таких цепочек выдается в качестве результата процедуры.

Height — высота леса. Процедура Height вычисляет высоту леса, заданного её параметром. Она равна длине самой длинной ветви по всем деревьям, входящим в данный лес, и выражается числом дуг, составляющих эту ветвь.

Leaves — множество листьев. Процедура Leaves выдает множество листьев, то есть концевых вершин леса, заданного её параметром.

Mark — метки вершин. Процедура Mark выдает множество меток, помечающих вершины, заданные её параметром.

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

Процедура Mask(q, r), где q — подавляемое состояние, r — цепочка резольверных символов прямого просмотра, выдает множество нетерминалов, входящих в состав меток конечных вершин — листьев тех ветвей разложения состояния q, которые помечены цепочкой r, если в метках этих ветвей игнорировать все семантические символы и резольверные символы обратного просмотра, то есть

Mask(q, r) =f {A | (A е N) &

& 3v: (v е Leaves(Selected branches(Develope(q), r)) & & (Mark(v) = "end-A"))}. Push-down list — магазинная цепочка. Эта процедура выдает цепочку магазинных символов, которая строится по лесу, заданному её параметром. Каждый новый магазинный символ, представляемый множеством нетерминальных вершин одного уровня, вносится в словарь магазинных символов Tf. Вот алгоритм её реализации.

Вход: f— лес, некоторое множество ветвей разложения некоторого состояния. Все ветви f имеют одинаковую длину.

Выход: а — цепочка магазинных символов из Г.

Метод:

а := s;

for i to Height(f)-1

do # Инициализация магазинной цепочки # X := {v | v е Vertex (f)}; # X — магазинный символ, множество

нетерминальных вершин f уровня i. # а := Xa; # Наращивание магазинной цепочки # if X g Г

then # Пополнение алфавита магазинных символов #

Г := Г u {X}

fi od

Return tree — дерево возвратных состояний. Эта процедура строит дерево возвратных состояний для подавляемого состояния q, заданного в качестве её параметра. Именно, строится корень дерева R = Repr(q), представляющий данное состояние q, и инициализируется дерево возвратных состояний: RT := R. Считается, что R принадлежит уровню 0.

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

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

for i from 0 while 3v: (v e Vertex^RT) &

3p: ((v = Repr(p)) & Suppressible(p)) do for Vv: ((v e Vertex;(RT)) & (p: ((v = Repr(p)) & Suppressible(p))))

# Здесь Vertexi(RT) — множество вершин дерева возвратных состояний RT уровня i. Равенство v = Repr(p) означает, что вершина v дерева возвратных состояний RT представляет состояние p. # do for УХ: (X е Г1)

do for У г: ((г е & (5^(р,Х, г) = q))

do # Провести дугу из вершины v во вновь создаваемую вершину w, которая представляет возвратное состояние q. Вершину w считать относящейся к уровню i + 1 # w := Repr(q); Create edge(v, w)

od

od od od

Selected branches — множество ветвей, помеченных данной резольверной цепочкой. Процедура Selected branches/ r), где f— некоторый лес, а r — цепочка резольверных символов прямого просмотра, выдает множество ветвей/, метки которых, если в них игнорировать все семантические символы и резольверные символы обратного просмотра, равны r.

Suppressible — тестирование подавляемого состояния. Процедура Suppressible (q), где q — некоторое состояние, выдает true, если состояние q — подавляемое, и false — в противном случае.

Vertex^ — множество вершин уровня i. Процедура Vertexi(f) выдаёт множество вершин уровня i в дереве или лесуf заданном её параметром.

4. ПОСТРОЕНИЕ УПРАВЛЯЮЩЕГО ПРОЦЕССОРА ОБРАТНОГО ПРОСМОТРА

Вход: % = (N, T, A, K, S) — управляющая граф-схема; Qf — множество состояний прямого просмотра2.

1 В приведённом далее алгоритме появление повторных образов подавляемых состояний не контролируется. Поэтому данный алгоритм «зацикливается», если дерево возвратных состояний оказывается бесконечным. Признак зацикливания упомянут в подстрочном замечании 2 на с. 8).

2 Напомним, что каждое состояние управления представляется как некоторое множество вершин управляющей граф-схемы.

Выход: Pcb = (Qb, Eb, Гь, Ab, 5b, qb , F) — искомый управляющий процессор обратного просмотра, где Qb — множество состояний, Zb — входной алфавит, Гь — магазинный алфавит, Ab — алфавит семантик, — алфавит резольверов, 5b = (5b,, 5b9) — управляющая

1 b* 2

таблица, состоящая из таблицы резольверов 5b1: Qb х (Zb u {в})^2эт и таблицы управляющих элементов

5b2: Qb х (Zb u {в}) х (Qb u {Pop}) х (Гь u {в}) х Ab*,

qb0 — начальное состояние, F с Qb — множество конечных состояний.

Метод:

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

Zb := Qf; Ab и такие, как в управляющей граф-схеме; qb0 := {v | v e Vertex(Gc):Mark(v) = "end-5"};

F := 0; Qb : = {qbo}; rb : = 0;

# Построение 5b #

for Vq: (q e <9b) # q — некоторое состояние обратного просмотра # do

for W: (/ e Zb) # t — некоторое состояние прямого просмотра # do E := Edges(t, q); # E — множество дуг граф-схемы, начала которых находятся в множестве t, а концы — в множестве q #

if E Ф 0

then # E — не пусто #

R:=Backward pass resolvers (E); # R — множество цепочек, состоящих из резоль-

верных символов обратного просмотра, входящих в состав контекстных цепочек, помечающих дуги множества E #

5b! (q,t):=R;

for Vr: (г е R) do

SE := Select edges(E, r); # SE — подмножество дуг E, метки которых, если в них

принимать во внимание только резольверные символы обратного просмотра, равны r #

р:=0-,

for Уе е SE do р :=р u Start(e) od;

# Определение семантики # с := Backward pass semantics(SE); if Ambiguous(c)

then Alarm (''Семантическая неоднозначность состояния ", q, ''по входу '', t, '' и резольверу '', r)

fi;

if Nonterminals(p)

then # p — нетерминальные вершины: прохождение правой границы терминального порождения некоторого понятия, помечающего одну из вершин множества p. # s:={v | (v e Vertex(Gc)) & (Mark(v) = "end-A") & (A e Mark(p))};

if s g Qb

then # s — новое состояние #

Qb := Qb u {s}

fi;

if p g rb

then # p — новый магазинный символ #

Гь := Гьu {p}; Qb := Qb u {p}

fi;

5b2(q, t, r) := (5, p, c) else # p состоит из терминальных вершин или начальной вершины заглавной компоненты управляющей граф-схемы # 5b2(q, t, r) := (p, в, c)

fi

od # r #

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

fi

od # t #;

5 := {v | (v e Vertex(%c)) & (Mark(v) = "begin-4") & (Succ(v) n q * 0)};

if 5 * 0

then # Достигнута левая граница терминального порождения некоторого понятия, являющегося меткой одной из вершин, входящих в множество, представляемое верхним символом магазина. # E := Edges (5, q); # E — множество дуг граф-схемы, начала которых находятся в множестве 5, а концы — в множестве q #

R := Backward pass resolvers (E); # R — множество цепочек, состоящих из резольверных символов обратного просмотра, входящих в состав контекстных цепочек, помечающих дуги множества E #

5\{q, в) =R-for V г. (г е R)

do SE := Select edges(E, r); # SE — подмножество дуг E, метки которых, если в них

принимать во внимание только резольверные символы обратного просмотра, равны r # # Определение семантики # c:=Backward pass semantics(SE); if Ambiguous (c)

then # Диагностика семантической неоднозначности # Alarm (''Семантическая неоднозначность состояния ", q, '' по в-входу и резольверу '', r)

fib;

5b2 (q, в, r) := (Pop, в, c)

od # r # od # q #;

F := {q e Qb | Edges({v0}, q) * 0, Mark(v0) = "begin-?'} # Конечными являются те состояния обратного просмотра, которые содержат

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

На этом заканчивается построение управляющего процессора обратного просмотра, а вместе с тем и построение всего челночного процессора.

Пример процессора, построенного по грамматике калькулятора, и его работу см. в [1].

5. ВСПОМОГАТЕЛЬНЫЕ АЛГОРИТМЫ ДЛЯ ПОСТРОЕНИЯ ОБРАТНОГО ПРОСМОТРА

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

Backward pass resolvers — резольверы обратного просмотра. Процедура Backward pass resolvers(E), где E — некоторое множество дуг управляющей граф-схемы, даёт множество цепочек резольверов обратного просмотра, заложенных1 в метки этих дуг.

Backward pass semantics — семантики обратного просмотра. Процедура Backward pass semantics(E), где E — некоторое множество дуг управляющей граф-схемы, выдаёт множество семантических цепочек обратного просмотра, заложенных2 в метки дуг множества E.

Edges — дуги. Процедура Edges(p, q), где p и q — некоторые множества вершин управляющей граф-схемы, выдаёт множество дуг, начала которых находятся в множестве p, а концы — в множестве q.

Nonterminals — нетерминалы. Процедура даёт результат true, если множество, заданное её параметром, состоит из нетерминальных вершин, и false — в противном случае.

Select edges — выборка подмножества дуг. Процедура Select edges(E, r) из множества дуг E отбирает те, которые помечены контекстными цепочками, в которые заложена цепочка резольверных символов обратного просмотра r.

Start — начало дуги. Процедура Start (e), где e — дуга, даёт вершину, из которой эта дуга выходит.

Все другие процедуры, используемые в алгоритме построения обратного просмотра, но здесь не определённые, описаны ранее в п. 3.

ЗАКЛЮЧЕНИЕ

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

1. Разложение любого состояния прямого просмотра конечно.

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

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

Все ветви разложения, листья которых помечены одинаковыми терминальными симво-

3

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

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

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

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

3. Разложение каждого состояния прямого просмотра сбалансировано по конечным листьям.

Ветви разложения, листья которых помечены метками вида "end-A", где A — нетерминалы (не обязательно одинаковые), относящиеся к одному и тому же контексту, должны иметь одинаковую длину. Выполнение этого требования гарантирует однозначное определение, сколько и каких магазинных символов следует записать в магазин перед тем, как использовать верхний символ магазина для определения возвратного состояния.

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

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

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

5. Каждый входной символ, принимаемый в подавляемом состоянии, не принимается ни в каком из возвратных состояний, производном от этого состояния и сопряжённых с ним магазинных символов.

Ограничение 5 надо воспринимать «рекурсивно». Нарушение этого ограничения означало бы неопределённость в действиях прямого просмотра — принимать ли текущий входной символ в текущем состоянии (считать текущий входной символ принадлежащим текущей конструкции) или его следует анализировать в возвратном состоянии (то есть отнести его к внешней конструкции).

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

1) управляющая грамматика не принадлежит классу грамматик, к которому применим метод автоматического синтеза языкового процессора типа, используемого в технологическом комплексе SYNTAX; необходимо построить эквивалентную грамматику требуемого класса;

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

Часто преследование второй из этих двух целей приводит одновременно и к достижению первой.

Литература

1. Мартыненко Б.К. Синтаксические диаграммы Н. Вирта и граф-схемы в Syntax- технологии // Компьютерные инструменты в образовании, 2014. № 2. С. 3-18.

2. Мартыненко Б.К. Синтаксически управляемая обработка данных. СПб.: Изд-во СПбГУ 2004.

3. Пересмотренное сообщение об Алголе 68 / Ред. А. Ван Вейнгаарден, Б. Майу, Дж. Пек, К. Костер, М. Синцов, Ч. Линдси, Л. Меертенс, Р. Фискер. М.: «Мир», 1979.

4. Алгол 68. Методы реализации / Под ред. Цейтина Г.С. Л.: Изд-во Ленингр. ун-та, 1976.

5. Мартыненко Б.К. Языки и трансляции. СПб.: Изд-во СПбГУ, 2013.

1 При условии, конечно, что начальный нетерминал не встречается в правой части этого КВОТ-правила грамматики.

SHUTTLE TRANSLATIONS IN THE SYNTAX-TECHNOLOGY

Martynenko B. K. Abstract

The method of creation contextually dependent spline shuttle processors used in SYNTAX-technology for implementation of syntactically controlled translations is described. The method is based on RBNF-grammars, represented in a form of modified N. Wirth's charts, graph-schemes. The processors possess the linear estimation of complexity on time concerning length of an input sentence.

Keywords: grammars, N. Wirth's syntactic flowcharts, graph-schemes, regular splines, translations.

(с) Наши авторы, 2014. Our authors, 2014.

Мартыненко Борис Константинович, доктор физико-математических наук, профессор кафедры информатики математико-механического фа кул ьтета СПбГУ,

[email protected]

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