
- •Формальные языки и грамматики Введение
- •1. Предварительные обсуждения
- •2. Формальные грамматики
- •3. Классификация формальных грамматик
- •4. Система составляющих
- •5. Синтаксические диаграммы
- •6. Синтаксическое дерево
- •7. Алгоритмы обхода вершин дерева разбора.
- •7.1 Алгоритм обхода "сверху-вниз".
- •7.2 Алгоритм обхода "снизу-вверх".
- •8. Двоичное дерево
- •9. Свойства двоичного дерева
- •10. Грамматический разбор цепочек
- •10.1. Разбор цепочки "сверху-вниз".
- •10.2. Разбор цепочки "снизу-вверх".
- •11. Операции над языками
- •Заключение
- •Контрольные вопросы и задачи
- •Индивидуальное задание
- •Указатель обозначений
- •Предметный указатель
- •Список литературы
- •1. Предварительные обсуждения.................................................... 4
4. Система составляющих
Последовательность терминальных и/или нетерминальных символов в цепочке формального языка всегда должна быть строго упорядочена. Однако, в процессе анализа текста эту цепочку нужно и можно расчленять на отдельные подцепочки и выполнять необходимые преобразования для каждой из них отдельно.
Для удобства введем условные обозначения синтаксических переменных и лексем на примере подмножества правил языка Паскаль:
синтаксические переменные: лексемы:
<программа> := J; "PROGRAM" := a1 ;
<заголовок-программы> := A1: "ALGEBRA" := a2 ;
<идентификатор-программы> := A2; "BEGIN" := a3;
<идентификатор-переменной> := A3: "END" := a4 ;
<блок> := B1; "I" := a5;
<раздел-операторов> := B2; ( 17 )
<оператор> := B3; ":=" := b1;
<оператор-присваивания> := B4; "+" := b2;
<переменная> := C1; "-" := b3;
<выражение> := C2; "x" := b4;
<терм> := C3; "/" := b5;
<множитель> := C4; ";" := c1;
<операция-сложения> := D1; "." := c2.
<операция-умножения> := D2;
Тогда подмножество правил языка Паскаль и значений синтаксических переменных, приведенное в примере 3, может быть записано так:
J ::=A1с1B1с2 ; C1 ::= A3 ;
A1 ::=a1A2 ; С2 ::= C3D1C3 ;
A2 ::=a2; C3 ::= C4D2C4 ;
A3 ::=I; C4 ::= C1; ( 18 )
В1 ::=В2 ; D1::= b2 | b3 ;
B2 ::=a3B3a4 ; D2 ::= b4 |b5 ;
B3 ::=B4 |... ;
B4 ::=C1b1C2 .
Последовательность вывода cинтаксически правильных цепочек от начального символа J имеет вид:
J => A1c1B1c2 => a1A2c1B1c2 => a1a2c1B1c2 => a1a2c1B2c2 => a1a2c1a3B3a4c2 => a1a2c1a3B4a4c2 => a1a2c1a3C1b1C2a4c2 => a1a2c1a3A3b1C2a4c2 => a1a2c1a3ib1C2a4c2 =>...
Вывод остановлен на синтаксической переменной С2, как в примере 4.
Последовательность вывода синтаксически правильных цепочек от начального символа С2 имеет вид:
C2 => C3D1C3 => C4D2C4D1C3 => C1D2C4D1C3 => A3D2C4D1C3 =>iD2C4D1C3 => ib4C4D1C3 => ib4C1D1C3 => ib4A3D1C3 => ib4iD1C3 =>ib4ib2C3 => ib4ib2C4D2C4 => ib4ib2C1D2C4 => ib4ib2A3D2C4 => ib4ib2iD2C4 => ib4ib2ib4C4 => ib4ib2ib4C1 => ib4ib2ib4A3 => ib4ib2ib4i.
Так получена цепочка терминальных символов для возможного алгебраического выражения. Любая перестановка символов в цепочке ведет к разрушению ее семантики.
Следует обратить внимание, что на каждом шаге вывода длина цепочки символов увеличивается. Это свойственно большинству формальных грамматик.
Длина цепочки равна числу символов в ней. Для := имеем || = 0,
Для := a1a2c1a3ib1C2a4c2 имеем | | = 9.
Если 1 и 2 -цепочки, то 12 также является цепочкой. Приписывание цепочки 2 справа к цепочке 1 называют конкатенацией.
Например,
если 1 = a1a2c1a3ib1 и 2 = C2a4c2 ,
то =12 = a1a2c1a3ib1C2a4c2 = J.
Пустую цепочку всегда можно приписать к синтаксически правильной цепочке справа или слева, не нарушая ее семантики,т.е.
= = = . ( 19 )
Если цепочка состоит из нескольких символов, то в ней всегда можно выделить "голову" и "хвост" цепочки.
"Головой" цепочки называется любая последовательность символов этой цепочки, начинающаяся с самого левого символа. Например, для цепочки , приведенной выше, это могут быть цепочки из множества:
{a1...; a1a2... ; a1a2c1...;... }. ( 20 )
"Хвостом" цепочки называется любая последовательность символов этой цепочки, оканчивающаяся самым правым символом. Например, для цепочки , приведенной выше, это могут быть цепочки из множества:
{ ...c2; ...a4c2; ...C2a4c2; ... }. ( 21 )
"Голова" называется правильной, если "хвост" - не пустая цепочка.
"Хвост" называется правильным, если "голова" - не пустая цепочка.
Выделение "головы" и "хвоста" цепочки обусловлены задачами экономии памяти компьютера и ускоренного синтаксического разбора текста программы при трансляции, когда оказывается удобным показать только "голову"( = 1... ) или только "хвост" ( = ... 2 ) цепочки.
Если цепочка 12выводима из цепочки 12c помощью одного правила Рi : ::= , то этот вывод записывают так:
12 => 12 ( 22 )
Если цепочка 12 выводима из цепочки 12c помощью нескольких правил i::= i при условии 1 = , 21, 3 => 2,,...n => , то этот вывод записывают так:
12 => 112 => 122 => ... => 1 ( 23 )
Если даны две цепочки и и вторая цепочка входит составной частью в первую, то это вхождение может быть описано так:
в круглых скобках на первом месте указывают имя второй цепочки, а на втором месте -номер символа первой цепочки, совпадающий с первым символом "головы" второй цепочки, т.е. ( , i ).
Если таких вхождений цепочки несколько, то формируется система составляющих первой цепочки вида:
C = { (; i); (; j); (; k);...}. ( 24 )
Например, СС2 = { (i,1);(i,3);(i,5);(i,7)}.
Если дана цепочка , которую можно разложить на синтаксически оформленные подцепочки 1;2;3;..., то система составляющих может быть записана так:
C{ ( 1, i ); ( 2, j ); ( 3, k );... }. ( 25 )
Например, CJ = { (i,5);(C2,7) }.
Для формирования системы составляющих необходимо, чтобы все составляющие цепочки либо не пересекались, либо были вложены одна в другую.
Например, система составляющих СС2 вложена в составляющую системы СJ.
Наличие системы составляющих существенно ускоряет разбор текста программы на стадии трансляции.