Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы, часть 2.doc
Скачиваний:
27
Добавлен:
01.05.2025
Размер:
80 Мб
Скачать
☆

[Править]Асимптотика

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

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

Пример грамматики для которой имеет значение порядок нетерминалов

 для 

Упорядочим множество нетерминалов по возрастанию индексов. Легко заметить, что правила для   будут представлять из себя все двоичные вектора длины  , а значит размер грамматики будет экспоненциальным. Если упорядочить нетерминалы по убыванию в грамматике изменений не будет.

[Править]Пример

Дана грамматика

Среди правил   непосредственной рекурсии нет, поэтому во время первой итерации внешнего цикла ничего не происходит. Во время второй итерации внешнего цикла правило   переходит в  .

Грамматика имеет вид

Устраняем левую рекурсию для 

Метод рекурсивного спуска (англ. Recursive descent parser) — алгоритм синтаксического анализа, реализуемый путём взаимного вызова парсящих процедур, соответствующих правилам контекстно-свободной грамматики или БНФ. Применения правил последовательно, слева-направо поглощают токены, полученные отлексического анализатора. Это один из самых простых алгоритмов парсинга, подходящий для полностью ручной реализации.

[Править]Варианты реализации [править]Предсказывающий парсер

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

Такой парсер работает за линейное время.

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

[Править]Парсер с возвратом

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

Такой парсер может потребовать экспоненциального времени работы, и не всегда гарантирует завершение, в зависимости от грамматики. Уязвим для левой рекурсии.

30.

31.

Виртуальные и динамические методы

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

Такой поиск еще называется поздним связыванием. Разница между методами заключается в особенности поиска адреса.

Когда компилятор встречает обращение к виртуальному методу, он подставляет вместо обращения к конкретному адресу код, который обращается к специальной таблице и извлекает оттуда нужный адрес. Эта таблица называется таблицей виртуальных методов (Virtual Method Table, VMT). Такая таблица есть для каждого объектного типа. В ней хранятся адреса всех виртуальных методов класса, независимо от того, унаследованы ли они от предка или перекрыты. Отсюда и достоинства, и недостатки виртуальных методов: они вызываются сравнительно быстро (но медленнее статических), однако для хранения указателей на них требуется большое количество памяти.

Динамические методы вызываются медленнее, но позволяют более экономно расходовать память. Каждому динамическому методу системой присваивается уникальный индекс. В таблице динамических методов (Dynamic Method Table, DMT) класса хранятся индексы и адреса только тех динамических методов, которые описаны в данном классе. При вызове динамического метода происходит поиск в этой таблице; в случае неудачи просматриваются все классы-предки в порядке иерархии и, наконец, TObject, где имеется стандартный обработчик вызова динамических методов. Экономия памяти налицо. Те, для кого это не очевидно, найдут подробности в разделе "Информация о типе времени выполнения (RTTI). Указатели на класс"

Когда компилятор встречает обращение к виртуальному методу, он подставляет вместо обращения к конкретному адресу код-смещение относительно начала специальной таблицы, из который и извлекается нужный адрес. Эта таблица называется таблицей виртуальных методов (Virtual Method Table, VMT). Такая таблица есть у каждого класса. В ней хранятся указатели (адреса) всех виртуальных методов класса: вновь объявленных и унаследованных. Отсюда достоинства и недостатки: они вызываются сравнительно быстро, хотя и медленнее статических, однако для хранения указателей требуется большее количество памяти. Доступ к виртуальному методу через VMT – это извлечение адреса по коду (смещению) из таблицы, состоящее из одной машинной инструкции.

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

• Директива Virtual всегда вводит новый виртуальный метод, никак не связанный с любым другим одноименным методом, наследуемым классом. Переопределенный виртуальный метод ведет себя аналогично переопределенному статическому методу, т.е. полиморфизм не проявляется. Переопределить виртуальный метод в потомке можно и статическим методом.

Type T1=Class Procedure Test; Virtual; End; T2=Class(T1) Procedure Test; // Test скрывается, но не замещается End; Var SomeObject: T1; Begin SomeObject:=T2.Create; SomeObject.Test; // Вызывается T1.Test

• У каждого производного класса свое пространство имен, предваряющее пространство имен всех наследуемых этим классом методов. Поэтому можно скрыть наследуемый метод, объявив одноименный виртуальный метод. Однако в VMT таблице сохраняется адрес нового и старого (переопределенного) виртуального метода, следовательно, к переопределенному виртуальному методу возможен доступ с использованием механизма приведения типов:

TParentClass(Obj). <метод>;