- •6. Генерация команд в компиляторе 44
- •1. Языки и грамматики
- •1.1. Язык как множество
- •1.2. Порождающая грамматика
- •1.3. Процесс порождения
- •1.4. Классификация грамматик по Хомскому
- •1.5. Классификация языков по Хомскому
- •1.6. Задача распознавания цепочек языка
- •2. Принципы трансляции языков программирования
- •3. Лексический анализ
- •3.1. Конечный автомат
- •3.2. Построение детерминированного конечного автомата
- •3.3. Недетерминированный конечный автомат
- •3.4. Преобразование неоднозначной а-грамматики к однозначной
- •3.5. Удаление из грамматики бесполезных нетерминалов
- •3.6. Лексический анализатор
- •4. Синтаксический анализ
- •4.1. Дерево порождения для кс-грамматики
- •4.2. Автомат с магазинной памятью
- •4.4. Левая рекурсия и ее устранение
- •4.5. Преобразование кс-грамматики к обобщенной нормальной форме Грейбах
- •4.6. Детерминированный ll-разбор
- •5. Обратная польская строка, как промежуточная форма программы
- •5.1. Обратная польская строка для арифметических выражений
- •5.2. Генерация опс для арифметических выражений
- •5.3. Вычисление опс для присваиваний и арифметических выражений с индексами
- •5.4. Генерация опс для присваиваний и арифметических выражений с индексами
- •5.5. Опс для условных, циклических и составных операторов
- •5.6. Опс для стандартных операторов
- •5.7. Распределение памяти и описание переменных
- •5.8. Обработка ошибок
- •6. Генерация команд в компиляторе
- •6.1. Распределение памяти при генерации команд
- •6.2. Генерация команд для присваиваний и арифметических выражений
- •6.3. Генерация команд с индексными выражениями
- •6.4. Генерация команд сравнения и перехода
5.2. Генерация опс для арифметических выражений
Преобразование арифметического выражения в ОПС можно выполнить в процессе работы анализатора. Например, в LL(1)-анализаторе для этого необходимо кроме основного магазина, куда в процессе работы записываются правые части порождающих правил, использовать синхронно работающий с ним дополнительный магазин. В этот дополнительный магазин будем записывать последовательность семантических действий, генерирующих элементы ОПС. Сами же действия по генерации ОПС будут выполняться при извлечении элементов из дополнительного магазина.
Для реализации такого алгоритма наряду с основной таблицей действий LL(1)-анализатора необходимо задать семантическую таблицу. Ее размеры в точности совпадают с основной таблицей, более того, для каждой непустой клетки основной таблицы, где находится правая часть какого-либо правила порождения, в семантической таблице помещается последовательность действий, количество которых равно длине правой части.
При этом надо учесть, что терминальные символы в КС-грамматике на самом деле являются лексемами, распознаваемыми лексическим анализатором. Некоторые из лексем, например имена переменных и константы, содержат дополнительную семантическую информацию – ссылки на таблицы переменных или таблицы констант, т.е. одинаковые терминальные символы в КС-грамматике семантически могут различаться.
Удобнее всего показать использование семантической таблицы на примере.
Пример 11. Пусть задана грамматика простых арифметических выражений, преобразованная к обобщенной нормальной форме Грейбах, та же самая, что в примере 8.
Табл. 13 в каждой клетке содержит действия LL(1)-анализатора, а ниже – синхронно выполняемые с ними семантические действия по генерации ОПС. В них знаком □ отмечены пустые действия, символом a – запись в ОПС операнда из входной цепочки (переменной или константы), символы + и * обозначают запись в ОПС знаков операций. Сами эти действия будут выполняться в момент выталкивания их из дополнительного магазина.
Табл. 13
-
+
*
(
)
a
┴
S
(S)VU
□□□□□
aVU
a□□
U
+ TU
□□+
λ
λ
λ
λ
λ
T
(S)V
□□□□
aV
a□
V
λ
* FV
□□*
λ
λ
λ
λ
F
(S)
□□□
a
a
Так как одинаковые терминальные символы a в КС-грамматике семантически могут различаться, будем во входной цепочке различные операнды обозначать разными символами: a, b и др., при этом все они будут соответствовать одному и тому же терминальному символу a. При этом операнды могут быть как именами переменных, так и константами.
Лексический анализатор, непосредственно анализирующий входную цепочку символов, на каждом шаге работы LL(1)-анализатора выдает ему тип лексемы. Если эта лексема – имя, а в магазине верхний символ a, то анализатор ищет это имя в таблице переменных, и если оно там будет найдено, то генерируется в ОПС тип переменной и ее номер в таблице. Если же такого имени в таблице нет, то это ошибка в анализируемом тексте программы, и анализатор должен выдать об этом диагностическое сообщение. Если очередная лексема – константа, то ее значение записывается в таблицу констант, а ее тип и номер в таблице констант генерируется в ОПС.
Пример работы LL(1)-анализатора с генерацией ОПС для входной цепочки a*(c + d) ┴ представлен в табл. 14.
Табл. 14
№ шага |
Входные символы |
Содержимое магазина |
Дополнит. магазин |
Порождающее правило |
ОПС |
1 |
a*(c + d) ┴ |
S ┴ |
□□ |
S → aVU |
|
2 |
a*(c + d) ┴ |
aVU ┴ |
a□□□ |
|
a |
3 |
*(c + d) ┴ |
VU ┴ |
□□□ |
V → * FV |
a |
4 |
*(c + d) ┴ |
*FVU ┴ |
□□*□□ |
|
a |
5 |
(c + d) ┴ |
FVU ┴ |
□*□□ |
F → (S) |
a |
6 |
(c + d) ┴ |
(S)VU ┴ |
□□□*□□ |
|
a |
7 |
c + d) ┴ |
S)VU ┴ |
□□*□□ |
S → aVU |
a |
8 |
c + d) ┴ |
aVU)VU ┴ |
a□□□*□□ |
|
a c |
9 |
+ d) ┴ |
VU)VU ┴ |
□□□*□□ |
V → λ |
a c |
10 |
+ d) ┴ |
U)VU ┴ |
□□*□□ |
U → + TU |
a c |
11 |
+ d) ┴ |
+TU )VU ┴ |
□□+□*□□ |
|
a c |
12 |
d) ┴ |
TU )VU ┴ |
□+□*□□ |
T → aV |
a c |
13 |
d) ┴ |
aVU )VU ┴ |
a□+□*□□ |
|
a c d |
14 |
) ┴ |
VU )VU ┴ |
□+□*□□ |
V → λ |
a c d |
15 |
) ┴ |
U )VU ┴ |
+□*□□ |
U → λ |
a c d + |
16 |
) ┴ |
)VU ┴ |
□*□□ |
|
a c d + |
17 |
┴ |
VU ┴ |
*□□ |
V → λ |
a c d + * |
18 |
┴ |
U ┴ |
□□ |
U → λ |
a c d + * |
19 |
┴ |
┴ |
□ |
|
a c d + * |
Рассмотренная грамматика простых арифметических выражений позволяет задавать формулы не только с операциями + и *, но и с некоторыми другими операциями. Тогда под обозначением + надо понимать и другие операции с таким же приоритетом, в частности, операцию – (минус), а под обозначением * еще и операцию / (делить). Заметим, что в заданной грамматике операция + имеет меньший приоритет, чем операция *. При этом конкретная операция, которая генерируется в ОПС, должна переписываться из анализируемой цепочки в дополнительный магазин, а уже оттуда – в ОПС.
Эту грамматику можно расширить для того, чтобы можно было записывать унарные операции (+ и –) перед операндом. Для этого достаточно добавить еще один нетерминал и порождающие правила:
F → +G
G → (S) | a
При работе анализатора по правилу F → +G в магазин следует записывать цепочку: +G□, а в дополнительный магазин: □□+, где под знаком + следует понимать группу унарных операций (+ и –), которые должны отличаться от бинарных.
Конец примера.