Рабочим названием платформы .NET было |
Динамическая генерация кода
Генерация развилок
Генерация кода, содержащего инструкции переходов, представляет некоторую сложность по сравнению с генерацией линейного кода. Дело в том, что появляются переходы вперед по коду, то есть переходы на инструкции, которые еще не были сгенерированы. Общий метод решения этой проблемы заключается в том, что такие инструкции переходов генерируются частично, то есть сначала вместо них в код вставляются заглушки, в которых не прописаны адреса переходов, а затем, когда адрес становится известен, заглушки заменяются на настоящие инструкции переходов.
Интересен факт, что генерация развилок существенно упрощается, если в процессе генерации придерживаться определенных требований структурированной парадигмы в программировании. Эти требования заключаются в том, что в генерируемой программе используются только пять структурных конструкций, а именно: последовательность (рис. 5.2a), выбор (рис. 5.2b), множественный выбор (рис. 5.2c), цикл с предусловием (рис. 5.2d) и цикл с постусловием (рис. 5.2e). При этом конструкции могут быть вложены друг в друга.
Структурные конструкции удобны тем, что имеют ровно один вход и ровно один выход. Этот факт в сочетании с тем, что они вкладываются друг в друга, позволяет использовать для их порождения рекурсивные алгоритмы. В данном разделе мы предложим как раз рекурсивный вариант генерации структурных конструкций.
Генерация кода для логических выражений
Логические выражения отличаются от рассмотренных ранее в этой главе арифметических выражений тем, что могут вычисляться не полностью. Например, в выражении
(a = 10) and (sin(x) = 0.5)
второе равенство имеет смысл вычислять, только если первое равенство истинно (то есть если значение переменной a равно 10).
Это означает, что в коде, вычисляющем логические выражения, должны активно использоваться условные переходы.
Абстрактный синтаксис логических выражений
Будем рассматривать логические выражения, которые содержат арифметические выражения, рассмотренные ранее, в качестве подвыражений. Пусть также логические выражения содержат операции сравнения (равно, меньше, больше) и логические операции (логическое И, логическое ИЛИ, логическое НЕ).
Дополним абстрактный синтаксис выражений, приведенный ранее в данной главе, новым нетерминалом LogExpr. Правила для этого нетерминала приведены в таблице 5.4.
Отображение абстрактного синтаксиса логических выражений в CIL
Аналогично функциям GenExpr из раздела приведенного ранее, определим набор функций GenLogExpr, которые отображают деревья абстрактного синтаксиса, соответствующие логическим выражениям, в CIL.
Напомним, что каждая функция принимает в качестве параметра дерево абстрактного синтаксиса и возвращает последовательность инструкций:
GenLogExpr[Expr] = GenExpr[Expr]; GenLogExpr[LogExpr1 ComparisonOp LogExpr2] = GenLogExpr[LogExpr1], GenLogExpr[LogExpr2], GenComparisonOp[ComparisonOp]; GenLogExpr[LogExpr1 and LogExpr2] = GenLogExpr[LogExpr1], dup, brfalse LABEL, GenLogExpr[LogExpr2], and, LABEL: ; GenLogExpr[LogExpr1 or LogExpr2] = GenLogExpr[LogExpr1], dup, brtrue LABEL, GenLogExpr[LogExpr2], or, LABEL: ; GenLogExpr[not LogExpr] = GenLogExpr[LogExpr], not; ComparisonOp[equal] = ceq; ComparisonOp[less] = нужный вариант инструкции clt; ComparisonOp[greater] = нужный вариант инструкции cgt;