
- •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.3. Вычисление опс для присваиваний и арифметических выражений с индексами
Присваивание можно определить как операцию, у которой первый операнд должен быть переменной, а второй – арифметическим выражением. При этом значение переменной хранится в некоторой области памяти (например, в таблице переменных), а результатом операции должно быть изменение этого значения. В отличие от других операций, после вычисления операции присваивания результат операции не должен сохраняться в магазине, т.е. магазин будет пустым.
Чтобы интерпретатор правильно вычислял как арифметические операции, так и операцию присваивания, для каждой ячейки магазина требуется хранить признак, указывающий, что в ней хранится – переменная или значение. Если на вход интерпретатора поступает операнд-константа, то должно записываться значение, а если переменная – то ссылка на ее размещение (например, на таблицу переменных). При поступлении на вход интерпретатора этот признак должен учитываться, и значения для операции должны либо извлекаться из магазина, либо по ссылке из таблицы переменных.
Пример 12. Дано присваивание x := a*(c + d). ОПС для него:
x a c d + *:=
В табл. 15 приведены шаги алгоритма вычисления ОПС.
Табл. 15
-
№
шага
Входные
символы
Содержимое
магазина
1
x a c d + * :=
2
a c d + * :=
x
3
c d + * :=
x
a
4
d + * :=
x
a
c
5
+ * :=
x
a
c
d
6
* :=
x
a
c+d
7
:=
x
a*(c+d)
8
Конец примера.
Выражения с индексами необходимы для доступа к элементам массивов. Для одномерного массива операция индексирования вычисляется следующим образом. Первый операнд такой операции – ссылка на таблицу переменных, где находится описание (паспорт) массива. В паспорте, в свою очередь, есть ссылка на расположение начального элемента массива с индексом 0, количество элементов, длина или тип каждого элемента. Второй операнд операции индексирования – значение индекса. Результатом операции является ссылка на индексируемый элемент массива. При этом вычисление ведется по формуле:
M + d*i,
где M – ссылка на элемент массива с индексом 0, d – длина элемента массива, i – значение индекса.
Для двумерного массива операция индексирования требует трех операндов: 1) ссылка на паспорт массива, 2) значение индекса по первому измерению, 3) значение индекса по второму измерению. При этом вычисление ведется по формуле:
M + d*(i*m + j),
где M – ссылка на элемент массива с индексом 0, d – длина элемента массива, m – количество элементов в массиве по второму измерению, i , j – значения индексов по первому и второму измерению соответственно.
По аналогичным формулам проводится вычисление в операции индексирования по трем и более индексам. Далее в примерах операцию индексирования по одному индексу будем обозначать <i>, а индексирование по двум индексам – <i2>.
При выполнении операции индексирования перед вычислением ссылки на индексируемый элемент массива можно выполнить проверку корректности индексов, и при выходе их за пределы массива останавливать вычисления с сигнализацией ошибки.
Пример 13. Дано присваивание с индексацией M[i] := a*L[i, j + d]. ОПС для него:
M i <i> a L i j d + <i2> * :=
В табл. 16 приведены шаги алгоритма вычисления ОПС. Для сокращения таблицы шаги 5 – 8 в ней пропущены.
Табл. 16
-
№
шага
Входные
символы
Содержимое
магазина
1
M i <i> a L i j d + <i2> * :=
2
i <i> a L i j d + <i2> * :=
M
3
<i> a L i j d + <i2> * :=
M
i
4
a L i j d + <i2> * :=
M[i]
9
+ <i2> * :=
M[i]
a
L
i
j
d
10
<i2> * :=
M[i]
a
L
i
j+d
11
* :=
M[i]
a
L[i, j+d]
12
:=
M[i]
a*L[i, j + d]
13
Конец примера.