- •Лабораторные работы
- •1. Порядок выполнения работы.
- •2. Содержание отчета.
- •Лабораторная работа № 1. Лабораторная работа № 1.1. Создание каркаса транслятора.
- •Лабораторная работа № 2 Лабораторная работа № 1.2. Разбор исходного файла.
- •Лабораторная работа № 3.
- •1. Порядок выполнения работы.
- •2. Содержание отчета.
- •Лабораторная работа № 5. Лабораторная работа №3.1. Синтаксический анализатор.
- •Лабораторная работа № 6. Лабораторная работа №3.2. Синтаксический анализатор.
- •Лабораторная работа № 7. Лабораторная работа №3.3. Синтаксический анализатор.
- •1. Порядок выполнения работы.
- •2. Содержание отчета.
- •Лабораторная работа №5. Разработка генератора кода
- •1. Порядок выполнения работы.
- •2. Теоретическая часть
- •Практическая часть.
- •Лабораторная работа № 9. Генератор кода 5.2.
- •4. Содержание отчета
- •5. Содержание отчета
- •Лабораторная работа № 11. Синтаксический анализатор.
- •Лабораторная работа №12. Генератор кода 5.3.
- •Варианты к лабораторным работам
- •Вариант 1
- •Вариант 2
- •Вариант 3
- •Вариант 4
- •Вариант 5
- •Вариант 6
- •Вариант 7
- •Вариант 8
- •Вариант 9
- •Вариант 10
- •Вариант 11
- •Вариант 12
- •Вариант 13
- •Вариант 14
- •Вариант 15
- •Вариант 16
- •Курсовой проект
- •Оформление
- •Пустые строки
- •Пробелы в строке
- •Локальные переменные
- •Комментарии
- •Инструкции (statements)
- •Оформление if, if-else, if-else if-else
- •Оформление for, foreach
- •Оформление while, do-while
- •Оформление switch
- •Оформление try-catch
- •Указания по оформлению псевдокода
Лабораторная работа №12. Генератор кода 5.3.
Общие принципы организации условного перехода в ассемблере. Инструкция cmp. Создание меток перехода, генерирование условных переходов для реализации инструкций while или if.
Ассемблерный код выполняется последовательно и построчно. Однако существует и возможность перейти к другому участку кода. Для этого необходимо поставить перед этим участком определенную метку. Безусловный переход к метке выполняется в ассемблере по инструкции jmp. Это унарная инструкция - в качестве единственного аргумента она принимает имя метки. Условный переход реализуется с помощью инструкций условных переходов, следующих за инструкцией cmp. При этом обычно переход к метке выполняется по невыполнению условия в коде. Все виды условных переходов представлены в таблице.
Инструкция |
Пояснение |
Код на «нашем» языке |
Код на ассемблере |
je |
jump equal |
a == b |
mov ax, a mov bx, b cmp ax, bx jne label |
jne |
jump not equal |
a != b |
mov ax, a mov bx, b cmp ax, bx je label |
jl |
jump |
a < b |
mov ax, a mov bx, b cmp ax, bx jge label |
jle |
jump less or equal |
a <= b |
mov ax, a mov bx, b cmp ax, bx jg label |
jg |
jump greater |
a > b |
mov ax, a mov bx, b cmp ax, bx jle label |
jge |
jump greater or equal |
a >= b |
mov ax, a mov bx, b cmp ax, bx jl label |
Метки, генерируемые для переходов в ассемблерном коде, будут носить неоригинальные названия – «label» плюс порядковый номер метки. В классе CodeGenerator заведем счетчик для хранения текущей используемой метки (этот счетчик сообщит и общее количество используемых меток), далее реализуем метод добавления метки в ассемблерный код и метод получения текущей метки.
private static int countLabels = 0;
добавитьМетку()
{
количествоМеток++;
}
Строка получитьТекущуюМетку()
{
Вернуть «label» + количествоМеток.вСтроку();
}
В синтаксическом анализаторе добавим поле хранящее имя текущей метки. Далее доработаем его методы.
tType разобратьВыражение()
{
tType t = разобратьСложениеИлиВычитание();
если( LexicalAnalyzer.текущаяЛексема == Lexems.Равно
|| LexicalAnalyzer.текущаяЛексема == Lexems.НеРавно
|| LexicalAnalyzer.текущаяЛексема == Lexems.Меньше
|| LexicalAnalyzer.текущаяЛексема == Lexems.Больше
|| LexicalAnalyzer.текущаяЛексема == Lexems.МеньшеИлиРавно
|| LexicalAnalyzer.текущаяЛексема == Lexems.БольшеИлиРавно )
{
Строка переход = «»;
switch( LexicalAnalyzer.текущаяЛексема )
{
case Lexems.Равно:
переход = «jne»;
break;
case Lexems.НеРавно:
переход = «je»;
break;
case Lexems.Больше:
переход = «jle»;
break;
case Lexems.БольшеИлиРавно:
переход = «jl»;
break;
case Lexems.Меньше:
переход = «jge»;
break;
case Lexems.МеньшеИлиРавно:
переход = «jg»;
break;
}
LexicalAnalyzer.разобратьСледующуюЛексему();
разобратьСложениеИлиВычитание();
CodeGenerator.добавитьИнструкцию( "pop ax" );
CodeGenerator.добавитьИнструкцию( "pop bx" );
CodeGenerator.добавитьИнструкцию( "cmp bx, ax" );
CodeGenerator.добавитьИнструкцию( переход + « » + текущаяМетка );
текущаяМетка = «»;
t = tType.Bool;
}
вернуть t;
}
разобратьВетвление()
{
проверитьЛексему( Lexems.If );
CodeGenerator.добавитьМетку();
Строка нижняяМетка = CodeGenerator.получитьТекущуюМетку();
текущаяМетка = нижняяМетка;
CodeGenerator.добавитьМетку();
Строка меткаДляВыхода = CodeGenerator.получитьТекущуюМетку();
разобратьВыражение();
проверитьЛексему( Lexems.Then );
разобратьПоследовательностьИнструкций();
CodeGenerator. добавитьИнструкцию( "jmp " + меткаДляВыхода );
пока( LexicalAnalyzer.текущаяЛексема == Lexems.ElseIf )
{
CodeGenerator. добавитьИнструкцию( нижняяМетка + «:» );
CodeGenerator.добавитьМетку();
нижняяМетка = CodeGenerator.получитьТекущуюМетку();
текущаяМетка = нижняяМетка;
LexicalAnalyzer.разобратьСледующуюЛексему();
разобратьВыражение();
проверитьЛексему( Lexems.Then );
разобратьПоследовательностьИнструкций();
CodeGenerator.добавитьИнструкцию( "jmp " + меткаДляВыхода );
}
если( LexicalAnalyzer.текущаяЛексема == Lexems.Else )
{
CodeGenerator.добавитьИнструкцию( нижняяМетка + «:» );
LexicalAnalyzer.разобратьСледующуюЛексему();
разобратьПоследовательностьИнструкций();
}
проверитьЛексему( Lexems.EndIf );
CodeGenerator. добавитьИнструкцию( меткаДляВыхода + «:» );
}
разобратьЦикл()
{
проверитьЛексему( Lexems.While );
CodeGenerator.добавитьМетку();
Строка верхняяМетка = CodeGenerator.получитьТекущуюМетку();
CodeGenerator.добавитьМетку();
Строка нижняяМетка = CodeGenerator.получитьТекущуюМетку();
текущаяМетка = нижняяМетка;
CodeGenerator.добавитьИнструкцию( верхняяМетка + «:» );
разобратьВыражение();
разобратьПоследовательностьИнструкций();
проверитьЛексему( Lexems.While );
CodeGenerator.добавитьИнструкцию( "jmp " + верхняяМетка );
CodeGenerator.добавитьИнструкцию( нижняяМетка + «:» );
}
Замечания по коду:
Так как строки в C# являются неизменяемым и ссылочным типом, приравнивание строк необходимо выполнять с копированием их значения - метод String.Copy();
Генерация ассемблерного кода для других видов цикла (for, do…while) реализуется аналогично.
Примеры кода:
Файлы SyntaxAnalyzer.cs, CodeGenerator.cs в проекте.
