Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab_tlpt_12_7.doc
Скачиваний:
1
Добавлен:
01.03.2025
Размер:
494.08 Кб
Скачать

Лабораторная работа №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.добавитьИнструкцию( нижняяМетка + «:» );

}

Замечания по коду:

  1. Так как строки в C# являются неизменяемым и ссылочным типом, приравнивание строк необходимо выполнять с копированием их значения - метод String.Copy();

  2. Генерация ассемблерного кода для других видов цикла (for, do…while) реализуется аналогично.

Примеры кода:

Файлы SyntaxAnalyzer.cs, CodeGenerator.cs в проекте.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]