Генерирование общих фрагментов кода, объявления переменных

Так как наш транслятор является однопроходным, методы генератора кода будут вызываться из методов синтаксического анализатора. По мере выполнения синтаксического разбора будет генерироваться и ассемблерный код. Для удобства будем хранить его в массиве строк. В классе CodeGenerator объявим массив строк и целочисленную переменную, хранящую текущий индекс для его правильного заполнения.

private static string[] code = new string[MAX_NUMBER_STRINGS];

private static int codePointer = 0;

Ключевым методом генератора кода будет метод добавитьИнструкцию(), добавляющий одну строку ассемблерного кода.

добавитьИнструкцию(инструкция)

{

код[указатель++] = инструкция;

}

Для ассемблерных программ некоторая часть кода является общей: объявление сегментов данных, кода и стека; инструкции завершения сегмента кода и т. д. Декларирование общих участков кода вынесем в отдельные функции.

Объявление сегмента данных (секции объявления переменных):

декларироватьСегментДанных()

{

добавитьИнструкцию("data segment para public \"data\"");

}

Объявление сегментов стека и кода:

декларироватьСегментыСтекаИКода()

{

добавитьИнструкцию("PRINT_BUF DB ' ' DUP(10)");

добавитьИнструкцию("BUFEND DB '$'");

добавитьИнструкцию("data ends");

добавитьИнструкцию("stk segment stack");

добавитьИнструкцию("db 256 dup (\"?\")");

добавитьИнструкцию("stk ends");

добавитьИнструкцию("code segment para public \"code\"");

добавитьИнструкцию("main proc");

добавитьИнструкцию("assume cs:code,ds:data,ss:stk");

добавитьИнструкцию("mov ax,data");

добавитьИнструкцию("mov ds,ax");

}

Объявление завершения основной процедуры:

декларироватьЗавершениеОсновнойПроцедуры()

{

добавитьИнструкцию("mov ax,4c00h");

добавитьИнструкцию("int 21h");

добавитьИнструкцию("main endp");

}

Объявление завершения кода:

декларироватьЗавершениеКода()

{

добавитьИнструкцию("code ends");

добавитьИнструкцию("end main");

}

Далее необходимо реализовать объявление переменных в ассемблерном коде.

декларироватьПеременные()

{

УзелСвязанногоСписка<Идентификатор> узел = nameTable.получитьИдентификаторы().Первый;

пока(узел!= НУЛЛ)

{

добавитьИнструкцию(узел.Значение.Имя + " dw 1");

узел = узел.Следующий;

}

}

Последним штрихом будет доработка метода SyntaxAnalyzer.компилировать(). Дополним его вызовом реализованных методов генератора кода.

компилировать()

{

CodeGenerator.декларироватьСегментДанных();

LexicalAnalyzer.инициализировать();

разобратьОбъявлениеПеременных();

CodeGenerator.декларироватьПеременные();

CodeGenerator.декларироватьСегментыСтекаИКода();

проверитьЛексему(Lexems.ПереносСтроки);

если(LexicalAnalyzer.текущаяЛексема == Lexems.Begin)

LexicalAnalyzer.разобратьСледующуюЛексему();

LexicalAnalyzer.разобратьСледующуюЛексему();

LexicalAnalyzer. разобратьПоследовательностьИнструкций();

проверитьЛексему(Lexems.End);

CodeGenerator.декларироватьЗавершениеОсновнойПроцедуры();

CodeGenerator.декларироватьЗавершениеКода();

}

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

1) Вывод ассемблерного кода на форму необходимо реализовать самостоятельно.

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

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: