Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Первая продукция, В —> ВВ, гласит, что конкатенация двух цепочек сбалансированных скобок сбалансирована. Это утверждение очевидно, поскольку можно сопоставить скобки в двух цепочках независимо друг от друга. Вторая продукция, В - н> (В), говорит, что если поместить пару скобок вокруг сбалансированной цепочки, то новая цепочка также будет сбалансированной. Это утверждение тоже очевидно, так как если скобки внутренней цепочки соответствуют друг другу, их можно удалить, и новые скобки становятся соседними. Третья продукция, В —> 8, является базисной, гласящей, что пустая цепочка сбалансирована.
Приведенные выше неформальные доводы должны убедить нас, что G/,ai порождает только цепочки сбалансированных скобок. Нам еще нужно доказать обратное: что каждая цепочка сбалансированных скобок порождается этой грамматикой. Однако доказательство индукцией по длине сбалансированной цепочки весьма просто и оставляется в качестве упражнения.
Мы отмечали, что множество цепочек сбалансированных скобок не является регулярным языком, и теперь докажем это. Если бы был регулярным, то для него по лемме о накачке для регулярных языков существовала бы константа п. Рассмотрим сбалансированную цепочку w = (")", т. е. п левых скобок, за которыми следуют п правых. Если разбить w = xyz в соответствии с леммой, то у состоит только из левых скобок, и цепочка xz содержит больше правых скобок, чем левых. Эта цепочка несбалансированна, т. е. получено противоречие с предположением, что язык сбалансированных скобок регулярен. □
Языки программирования содержат, конечно же, не только скобки, но скобки составляют существенную часть арифметических и условных выражений. Грамматика, изображенная на рис. 5.2, более типична для структуры арифметических выражений, хотя там использованы всего два оператора, сложения и умножения, и включена детальная структура идентификаторов, которая, вероятней всего, обрабатывалась бы лексическим анализатором компилятора, как мы упоминали в разделе 3.3.2. Однако язык, представленный на рис. 5.2, также нерегулярен. Например, в соответствии с этой грамматикой, (па)п является правильным выражением. Мы можем использовать лемму о накачке для того, чтобы показать, что если бы язык был регулярным, то цепочка с некоторыми удаленными левыми скобками, символом а и всеми нетронутыми правыми скобками также была бы правильным выражением, что неверно.
Многие объекты типичного языка программирования ведут себя подобно сбалансированным скобкам. Обычно это сами скобки в выражениях всех типов, а также начала и окончания блоков кода, например, слова begin и end в языке Pascal, или фигурные скобки { и } в С. Таким образом, любое появление фигурных скобок в С-программе должно образовывать сбалансированную последовательность с { в качестве левой скобки и } — правой.
Есть еще один способ балансирования "скобок", отличающийся тем, что левые скобки могут быть несбалансированны, т. е. не иметь соответствующих правых. Примером является обработка if и else в С. Произвольная if-часть может быть как сбалансирована, так и не сбалансирована некоторой else-частью. Грамматика, порождающая возможные последовательности слов if и else, представленных /' и е соответственно, имеет следующие продукции.
S->e\SS\iS\iSeS
Например, ieie, iie и iei являются возможными последовательностями слов if и else, и каждая из этих цепочек порождается данной грамматикой. Примерами неправильных последовательностей, не порождаемых грамматикой, являются е/ и /ее/7.
Простая проверка (доказательство ее корректности оставляется в качестве упражнения) того, что последовательность символов / не порождается грамматикой, состоит в рассмотрении каждого е по очереди слева направо. Найдем первое /' слева от рассматриваемого е. Если его нет, цепочка не проходит проверку и не принадлежит языку. Если такое /' есть, вычеркнем его и рассматриваемое е. Затем, если больше нет символов е, цепочка проходит проверку и принадлежит языку. Если символы е еще есть, то проверка продолжается.
Пример 5.20. Рассмотрим цепочку /ее. Первое е соответствует / слева от него. Оба удаляются. Оставшееся е не имеет / слева, и проверка не пройдена; слово /ее не принадлежит языку. Отметим, что это заключение правильно, поскольку в С-программе слов else не может быть больше, чем if.
В качестве еще одного примера рассмотрим iieie. Соответствие первого е и / слева от него оставляет цепочку iie. Соответствие оставшегося е и /' слева оставляет /'. Символов е больше нет, и проверка пройдена. Это заключение также очевидно, поскольку последовательность iieie соответствует С-программе, структура которой подобна приведенной на рис. 5.10. В действительности, алгоритм проверки соответствия (и компилятор С) говорит нам также, какое именно if совпадает с каждым данным else. Это знание существенно, если компилятор должен создавать логику потока управления, подразумеваемую программистом. □
if (Условие) {
if (Условие) Инструкция; else Инструкция;
if (Условие) Инструкция; else Инструкция;
}
Рис. 5.10. Структура if-else; два слова else соответствуют предыдущим if, а первое if несбалансированно
5.3.2. Генератор синтаксических анализаторов YACC
Генерация синтаксического анализатора (функция, создающая деревья разбора по исходным программам) воплощена в программе YACC, реализованной во всех системах UNIX. На вход YACC подается КС-грамматика, запись которой отличается от используемой здесь только некоторыми деталями. С каждой продукцией связывается действие (action), представляющее собой фрагмент С-кода, который выполняется всякий раз, когда создается узел дерева разбора, соответствующий (вместе со своими сыновьями) этой продукции. Обычно действием является код для построения этого узла, хотя в некоторых приложениях YACC дерево разбора не создается, и действие задает что-то другое, например, выдачу порции объектного кода.
Пример 5.21. На рис. 5.11 показан пример КС-грамматики в нотации YACC. Грамматика совпадает с приведенной на рис. 5.2. Мы опустили действия, показав лишь их (требуемые нотацией) фигурные скобки и расположение во входной последовательности YACC.
Exp : Id { . ..}
| Exp ' + ' Exp {.• . }
| Exp '*' Exp {••.}
| ' (' Exp ') ' { . - . } t
Id : 'a' {...}
'b' {...}
| Id 'a' { . . . }
| Id 'b' {...}
| Id '0' {•■.}
| Id '1' {...}
r
Рис. 5.11. Пример грамматики в нотации YACC
Отметим следующие соответствия между нотацией YACC и нашими грамматиками.
- Двоеточие используется в качестве символа продукции — Все продукции с данной головой группируются вместе, и их тела разделены вертикальной чертой. Список тел для данной головы заканчивается точкой с запятой. Завершающий символ не используется. Терминалы записываются в апострофах. Некоторые буквы могут появляться в одиночных апострофах. Хотя у нас они не показаны, YACC позволяет пользователю определять также и символические терминалы. Появление таких терминалов в исходной программе обнаруживает лексический анализатор и сигнализирует об этом синтаксическому анализатору через свое возвращаемое значение. Цепочки символов и цифр, не взятые в апострофы, являются именами переменных. Мы воспользовались этой возможностью для того, чтобы дать нашим переменным более выразительные имена— Ехр и Id, хотя можно было использовать Ew. I.
□
5.3.3. Языки описания документов
Рассмотрим семейство "языков", которые называются языками описания документов (markup languages). "Цепочками" этих языков являются документы с определенными метками, которые называются дескрипторами (tags). Дескрипторы говорят о семантике различных цепочек внутри документа.
Читатель, возможно, знаком с таким языком описания документов, как HTML (Hypertext Markup Language). Этот язык имеет две основные функции: создание связей между документами и описание формата ("вида") документа. Мы дадим лишь упрощенный взгляд на структуру HTML, но следующие примеры должны показать его структуру и способ использования КС-грамматики как для описания правильных HTML - документов, так и для управления обработкой документа, т. е. его отображением на мониторе или принтере.
Пример 5.22. На рис. 5.12, а показан текст, содержащий список пунктов, а на рис. 5.12, б— его выражение в HTML. На рис. 5.12, б, показано что HTML состоит из обычного текста, перемежаемого дескрипторами. Соответствующие друг другу, т. е. парные дескрипторы имеют вид <х> и </х> для некоторой цепочки х.15 Например, мы видим парные дескрипторы <ЕМ> и </ЕМ>, которые сигнализируют, что текст между ними должен быть выделен, т. е. напечатан курсивом или другим подходящим шрифтом. Мы
видим также парные дескрипторы <0L> и </OL>, указывающие на упорядоченный список, т. е. на нумерацию элементов списка. Вещи, которые я ненавижу.
- Заплесневелый хлеб. Людей, которые ведут машину по узкой дороге слишком медленно.
а) видимый текст <Р>Вещи, которые я <ЕМ>ненавижу</ЕМ>: <OL>
<Ы>Заплесневелый хлеб.
<Ы>Людей, которые ведут машину по узкой дороге слишком медленно. </OL>
6) исходный HTML-текст Рис. 5.12. HTML-документ и его видимая версия
Мы видим также два примера непарных дескрипторов: <Р> и <LI>, которые вводят абзацы и элементы списка, соответственно. HTML допускает, а в действительности поощряет, чтобы эти дескрипторы сопровождались парными им </Р> и </LI> на концах абзацев и списков, однако не требует этого. Поэтому эти парные дескрипторы не рассматриваются, что обеспечивает некоторую сложность нашей HTML-грамматике, развиваемой далее. □
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |


