
- •Теория вычислительных процессов и структур
- •1. Предварительные математические сведения
- •1.2. Операции над множествами Объединение множеств
- •Пересечение множеств
- •Разность множеств
- •1.3. Множества цепочек
- •1.4. Языки
- •1.5. Алгоритмы
- •1.6. Некоторые понятия теории графов
- •2. Введение в компиляцию
- •2.1. Задание языков программирования
- •2.2. Синтаксис и семантика
- •2.3. Процесс компиляции
- •2.4. Лексический анализ
- •2.5. Работа с таблицами
- •2.6. Синтаксический анализ
- •2.7. Генератор кода
- •Алгоритм.
- •2.8. Оптимизация кода
- •2.9. Исправление ошибок
- •2.10. Резюме
- •3. Теория языков
- •3.1. Способы определения языков
- •3.2. Грамматики
- •Пример.
- •3.3. Грамматики с ограничениями на правила
- •3.4. Распознаватели
- •3.5. Регулярные множества, их распознавание
- •3.6. Регулярные множества и конечные автоматы
- •3.7. Графическое представление конечных автоматов
- •3.8. Конечные автоматы и регулярные множества
- •3.9. Минимизация конечных автоматов
- •3.10. Контекстно-свободные языки
- •3.10.1. Деревья выводов
- •3.10.2. Преобразование кс–грамматик
- •3.10.3. Грамматика без циклов
- •3.10.4. Нормальная форма Хомского
- •3.10.5. Нормальная формула Грейбах
- •3.11. Автоматы с магазинной памятью
- •3.11.1. Основные определения
- •3.11.2. Эквивалентность мп-автоматов и кс-грамматик
- •4.1. Эквивалентность мп-автоматов и кс-грамматик
- •4.2. Ll(1)-грамматики
- •4.3. Ll(1)-таблица разбора
- •5. Синтаксический анализ снизу вверх
- •5.1. Разбор снизу вверх
- •5.2. Lr(1) - таблица разбора
- •5.3. Построение lr – таблицы разбора
- •5.4. Сравнение ll – и lr – методов разбора
- •6. Включение действий в синтаксис
- •6.1. Получение четверок
- •6.2. Работа с таблицей символов
- •7. Проектирование компиляторов
- •7.1. Число проходов
- •7.2. Таблицы символов
- •Identifier, type.
- •Int procedure rehash(int n)
- •Int procedure rehash(int n)
- •7.3. Таблица видов
- •8. Распределение памяти
- •8.1. Стек времени прогона
- •Integer a, b, X, y
- •Int table[1:10, -5:5].
- •8.2. Методы вызова параметров
- •8.3. Обстановка выполнения процедур
- •8.4. «Куча»
- •8.5. Счетчик ссылок
- •8.6. Сборка мусора
- •9. Генерация кода
- •(Тип – адреса, номер - блока, смещение).
- •9.2. Структура данных для генерации кода
- •9.3. Генерация кода для типичных конструкций
- •9.3.1. Присвоение
- •9.3.2. Условные зависимости
- •If b then c else d
- •9.3.3. Описание идентификаторов
- •9.3.4. Циклы
- •9.3.5. Вход и выход из блока
- •9.3.6. Прикладные реализации
- •9.4. Проблемы, связанные с типами
- •9.5. Время компиляции и время прогона
- •10. Исправление и диагностика ошибок
- •10.1. Типы ошибок
- •10.2. Лексические ошибки
- •10.3. Ошибки в употреблении скобок
- •Begin end
- •Case esac
- •10.4. Синтаксические ошибки
- •10.5. Методы исправления синтаксических ошибок
- •End begin
- •10.6. Предупреждения
- •10.7. Сообщения о синтаксических ошибках
- •10.8. Контекстно-зависимые ошибки
- •Identifier xyz not declared
- •Identifier blank alredy declared in block
- •10.9. Ошибки, связанные с употреблением типов
- •Int I; char c;
- •10.10. Ошибки, допускаемые во время прогона
- •10.11. Ошибки, связанные с нарушением ограничений
2.4. Лексический анализ
Входом компилятора, а, следовательно, и лексического анализатора, служит цепочка символов некоторого алфавита.
Работа лексического анализатора состоит в том, чтобы сгруппировать отдельные терминальные символы в единые синтаксические объекты – лексемы. Какие объекты считать лексемами, зависит от входного языка программирования.
Лексема – цепочка терминальных символов, с которой мы связываем лексическую структуру, состоящую из пары вида (тип лексемы, некоторые данные). Первой компонентой пары является синтаксическая категория, такая как «константа» или «идентификатор», а второй указатель: в ней указывается адрес ячейки, хранящей информацию о конкретной лексеме. Для данного языка число типов лексем считается конечным.
Обычно пару (тип лексемы, указатель) называют лексемой.
Таким образом, лексический анализатор – это транслятор, входом которого служит цепочка символов, представляющая программу, а выходом – последовательность лексем.
Этот выход образует вход синтаксического анализатора.
Пример.
Оператор Фортрана
COST=(PRICE+TAX)*0.98.
Лексический анализ:
COST, PRICE и TAX – лексемы типа <идентификатор>;
0.98 – лексема типа <константа>;
=, +, * - сами являются лексемами.
Пусть все константы и идентификаторы можно отображать в лексемы типа <идентификатор>. Предполагаем, что вторая компонента лексемы представляет собой указатель элемента таблицы, содержащей фактическое имя идентификатора вместе с другими данными об этом конкретном идентификаторе.
Первая компонента используется синтаксическим анализатором для разбора.
Вторая компонента используется на этапе генерации кода для изготовления объектного модуля.
Таким образом, выходом лексического анализатора будет последовательность лексем
<ИД1>=(<ИД2>+<ИД3>)*<ИД4>.
Вторая часть компоненты лексемы (указатель) – показана в виде индексов. Символы = + * трактуются как лексемы, тип которых представляется ими самими. Они не имеют связанных с ними данных и, следовательно, не имеют указателей.
Лексический анализ легко проводить, если лексемы, состоящие более чем из одного знака, изолированы с помощью знаков, которые сами являются лексемами (*, +, =).
Однако, в общем случае лексический анализ выполнить не так легко.
Рассмотрим два правильных предложения Фортрана:
DO 10 I=1.15;
DO 10 I=1,15.
В операторе 1) цепочка DO 10 I – переменная, а цепочка 1.15 – константа.
В операторе 2) DO – ключевое слово, 10 – константа, I – переменная, 1 и 15 константы, т.е. операция «найти очередную лексему» закончится лишь тогда, когда анализатор дойдет до DO или DO 10 I. Таким образом лексических анализатор должен заглядывать вперед за интересующую его в данный момент лексему.
Другие языки, например PL/1, вообще требуют заглядывать при лексическом анализе вперед сколь угодно далеко.
Однако, существует другой подход к лексическому анализу, менее удобный, но позволяющий избежать проблемы произвольного заглядывания вперед.
Существует два крайних подхода к лексическому анализу.
Лексический анализатор работает прямо, если для данного входного текста (цепочки) и положения указателя в этом тексте анализатор определяет лексему, расположенную непосредственно справа от указанного места и сдвигает указатель вправо от части текста образующего лексему.
Лексический анализатор работает не прямо, если для данного текста, положения указателя в этом тексте и типа лексемы он определяет, образуют ли знаки, расположенные непосредственно справа от указателя, лексему этого типа. Если да, то указатель передвигается вправо от части текста, образующей эту лексему.