Читайте данную работу прямо на сайте или скачайте

Скачайте в формате документа WORD


Трансляция всех модификаций команд add и cmp

Введение

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

из языков программирования в некоторую стандартнуюа форму, называемую

объектной программой. Существует три вида трансляторов: ассемблеры, компиляторы и интерпретаторы.

Транслятор, преобразующий программу, написанную на языке ассемблера, в машинный код, называется ассемблером. При написании программы на

языке ассемблера программист использует мнемонические обозначения машинных команд и адресов (имена и метки). В процессе трансляцииа ассемблер

заменяет все мнемонические обозначения (коды команд и имена) их двоичными кодами. Для сокращения текста при повторении идентичных частей программы в отдельные языки ассемблера введены средства написания и обработки макрокоманд. Это позволяет программисту определить некоторую последовательность команд как макроопределение, которое обрабатывается макроссемблером (макропроцессором). Последний представляет тексты макроопределений с соответствующими фактическими параметрамиа макровызов вместо

макрокоманд в программе.

Простейший ассемблер является однопроходным и преобразуета исходную

программу за один просмотр. Но при этом возникают трудности, связанные с

вычислением адресов имен, которые определены позже. Этого можно избежать, потребовав, чтобы все имена данных были объявлены заранее, неопределенные адреса заносились в таблицу, в которую вводятся ссылки вперед. Эта таблица либо используется для модификации команды, либо загрузчиком, который может формировать данный адрес во время загрузки. Однако

это не всегда удобно, поэтому большинство ассемблеров выполняюта ва два

прохода.

Основная идея двухпроходного ассемблера проста. На первома проходе

все символы (имена, метки) собираются в таблицу символов с соответствующими значениями адресов, на втором генерируется машинная программ на

основании построенной на первом проходе таблицы символов.

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

тексты макроопределений, если они есть в исходной программе, сохраняются, вместо макровызовов подставляются ассемблерные команды из макроопределений. Возможно также объединение макропроцессора с первым проходом

ассемблера, что сокращает время трансляции, но длиняет текст ассемблера.


;█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█

;█ ----- ТРАНСЛЯЦИЯ ВСЕХ МОДИФИКАЦИЙ КОМАНДЫ ADD ----- █

;█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█

.MODEL TINY

.CODE

JUMPS

ORG 100h

begin:

jmp general

;┌──────────────────────────────────────┐

;│ Макрос вывода на экран строки stirng │

;└──────────────────────────────────────┘

Wrt macro string

mov ah,9 ; Функция вывода строки

lea dx,string ; Загружаем адрес строки

int 21h ; Вызов прерывания DOS

endm

;┌──────────────────────────────┐

;│ Основная процедура программы │

;└──────────────────────────────┘

general procа near

pushа cs ; Все

pushа cs ; сегменты

pushа cs ; приравниваем

pop ds ; к сегменту

pop es ; кода

pop ss ; (необходимо для строковых операций)

Wrt about ; Вывод информации о программе

; Начинаем разбор строки параметров

mov cl,ds:[80h] ; Получаем длину строки параметров

sub ch,ch ; Обнуляем ch

cmp cx,2 ; Смотрим длину строки параметров

jb source_error ; Если она меньше двух - нет вх.файла

mov di,82hа ; Заносим в DI адрес начала поиска

mov path1,di ; Запоминаем адрес входного файла

mov al,' 'а ; Искать будем до первого пробела

repne scasb ; Запускаем цикл поиска

jne dest_error ; Если не нашли значет нет вых. файла

mov byte ptr [di-1],0 ; Приводим к формату ASCIIZ

mov path2,di ; Запоминаем адрес выходного файла

mov cl,ds:[80h] ; Заносим в cl длину строки поиска

sub ch,ch ; Обнуляем ch

mov al,13 ; Искать будем до символа CR

repne scasb ; Запуск цикла поиска

jne dest_error ; Если не нашли значет нет вых. файла

mov byte ptr [di-1],0 ; Приводим к формату ASCIIZ

callа Fopen ; Открываем входной файл

jc open_source_error ; Если ошибка, выдаем сообщение

callа Fcreate ; Создаем выходной файл

jc create_dest_error ; Если ошибка, выдаем сообщение

gen1: callа Fread ; Считываем очередную строку из файла

jc read_error ; Переход если ошибка

cmp EOF,1 ; Смотрим признак конца файла

jne gen2 ; Если не конец, продолжаем

cmp si,0 ; Проверяем длину строки

jne gen2 ; Если не 0 символов продолжаем

jmp read_error ; Иначе выводим сообщение об ошибке

gen2: inc string ; Увеличиваем счетчик строк

mov strlen,si ; Запоминаем длину строки

callа DelSpc ; Вызываем процедуру даления пробелов

cmp strlen,2 ; Если длина строки 2 символа, то

je gen1 ; переходим на чтение следующей

lea di,buffer ; Загружаем адрес строки

cmp byte ptr [di],';' ; Если первый символ строки ; то

je gen1 ; переходим на чтение следующей

lea si,command ; Будем искать строку ADD

mov cx,3 ; Длина искомой строки 3 символа

repeа cmpsb ; Начинаем поиск

je gen3 ; Переход, если ADD найдена

wrt error06 ; Вывод сообщения об ошибке

callа WrtStr ; Вывод ошбочной строки

mov was_error,1 ; Устанавливаем флаг ошибки

jmp gen1 ; Переход на чтение следующей строки

gen3: callа Coding

cmp was_error,0

jne gen1

callа Fwrite

jnc gen1

ret

gen4: mov bx,dest ; Если трансляция проведена спешно

callа Fclose ; Закрываем выходной файл

Wrt mes2 ; Вывод сообщения о завершении

Wrt mes3 ; Вывод сообщения о строках

callа WrtStr ; Вывод числа обработаных строк

Wrt mes1 ; Вывод CR,LF

ret ; ВЫХОД В DOS

; Далее располагаются метки перехода по различным ошибкам

source_error:

Wrt error01

ret

dest_error:

Wrt error02

ret

open_source_error:

Wrt error03

ret

create_dest_error:

Wrt error04

ret

read_error:

cmp EOF,1 ; Смотрим был ли конец файла

je skip_err_messageа ; Если да, то это не ошибка

Wrt error05 ; Иначе выводим сообщение об ошибке

mov was_error,1 ; Устанавливаем флаг ошибки

skip_err_message:

mov bx,source ; Заносим дескриптор выходного файла

callа Fclose ; Закрываем выходной файл

cmp was_error,0 ; Смотрим флаг ошибки

je gen4 ; Если ошибок нет, то переход

callа Fdel ; Иначе даляем выходной файл

Wrt mes1 ; Вывод CR,LF

Wrt bell ; Вывод сигнала

ret

general endp

;┌──────────────────────────────────────────────────────┐

; Переводит значение регистра AX в десятичный формат │

;└──────────────────────────────────────────────────────┘

Decimal procа near

callа clear ; Очищаем строку вывода

mov cx,0010 ; Заносим в CX делитель

lea si,outstr+4 ; Указатель на конец строки

b20:а cmp ax,0010 ; Сравниваем AX с 10

jb short b30 ; Переход, если меньше

xor dx,dx ; Обнуляем DX

div cx ; Делем AX на CX

or dl,30h ; Добавляем 48, чтобы получить 1

mov [si],dl ; Заносим в выходную строку

dec si ; Движемся влево

jmp short b20 ; Переход на следующий символ

b30:а or al,30h ; Добавляем 48, чтобы получить 1

mov [si],al ; Заносим в выходную строку

ret

; Вспомогательная процедура. Очищает строку outstr (забивает нулями)

clear procа near

lea si,outstr ; Загружаем адрес выходной строки

mov cl,48 ; 48 - символ нуля

mov [si],cl ; Забиваем

mov [si+1],cl ; нулями

mov [si+2],cl ; все

mov [si+3],cl ; символы

mov [si+4],cl ; строки

ret ; Выход

clear endp

outstr db ' $'

Decimal endp

;┌──────────────────────────────┐

;│ Процедура вывода числа строк │

;└──────────────────────────────┘

WrtStr procа near

xor ax,ax ; Обнуление регистра AX

mov al,string ; В AL число обработанных строк

callа Decimal ; Преобразуем в десятичный формат

Wrt outstr ; Выводим на экран

ret ; Выход

WrtStr endp

;┌─────────────────────────────┐

;│ Процедура даления пробелов │

;└─────────────────────────────┘

DelSpc procа near

cld ; станавливаем флаг направления

lea si,buffer ; Заносим в SI адрес буфера

mov di,si ; Дублируем в DI

mov cx,strlen ; В CX длина считанной строки

xor bx,bx ; Обнуляем BX

mov dl,1 ; словие цикла

del1: lodsb ; Загружаем в AL один байт

cmp al,65 ; A?

jb del2 ; Переход если меньше

cmp al,90 ; Z?

ja del2 ; Переход если больше

add al,32 ; Иначе перевод F-f

xor dl,dl ; Обнуляем DL

jmp del4 ; Переход на запись символа

del2: cmp al,' ' ; Пробел?

je del3 ; Если да, то переход

xor dl,dl ; Обнуляем DL

jmp del4 ; Переход на запись символа

del3: cmp dl,1 ; DL=1?

je del5 ; Если да, то переход

mov dl,1 ; Заносим в DL 1

del4: stosb ; Запись символа в строку

inc bx ; Увеличиваем счетчик символов

del5: loopа del1 ; Цикл

mov strlen,bx ; Заносим длину преобразованной строки

ret ; Выход

DelSpc endp

;┌──────────────────────────┐

;│ Процедура открытия файла │

;└──────────────────────────┘

Fopen procа near

mov ah,3dhа ; Функция открытия файла

xor al,al ; Открываем на чтение (AL=0)

mov dx,path1 ; Адрес ASCIIZ строки файла

int 21h ; Вызов прерывания DOS

jnc ok1 ; Переход, если открытие спешно

stc ; становка флага переноса

ret ; Выход

ok1:а mov source,ax ; Запоминаем дескриптор файла

ret ; Выход

Fopen endp

;┌──────────────────────────┐

;│ Процедура создания файла │

;└──────────────────────────┘

Fcreate procа near

mov ah,3chа ; Функция создания файла

xor cx,cx ; Заносим атрибут файла в CX

mov dx,path2 ; Адрес ASCIIZ строки файла

int 21h ; Вызов прерывания DOS

jnc ok2 ; Переход, если файл создан спешно

mov ah,3ch ; Если выходной файл не задан

xor cx,cx ; Устанавливаем по молчанию

lea dx,default ; Имя OUT.COM

int 21h ; Пытаемся создать файл

jnc ok2 ; Если получилось - на выход

stc ; становка флага переноса

ret ; Выход

ok2:а mov dest,ax ; Запоминаем дескриптор файла

ret ; Выход

default db 'OUT.COM',0

Fcreate endp

;┌──────────────────────────┐

;│ Процедура закрытия файла │

;└──────────────────────────┘

Fclose procа near

mov ah,3ehа ; Функция закрытия файла

int 21h ; Вызов прерывания DOS

jnc ok3 ; Переход, если файл спешно закрыт

Wrt error05а ; Вывод сообщения об ошибке

ok3:а ret ; Выход

Fclose endp

;┌────────────────────────┐

;│ Процедура чтения файла │

;└────────────────────────┘

Fread procа near

lea dx,buffer ; Загружаем адрес буфера

mov di,dx ; Запоминаем адрес начала буфера в DI

xor si,si ; Обнуляем SI

mov bx,source ; Заносим в BX дескриптор файла

mov cx,1 ; Число символов для чтения

frd1: mov ah,3fh ; Функция чтения из файла

int 21h ; Вызов прерывания DOS

jnc frd2 ; Переход, если нет ошибки

wrt error05 ; Вывод сообщения об ошибке

stc ; станавливаем флаг переноса

ret ; Выход

frd2: cmp ax,0 ; Если AX=0, то достигнут конец файла

je end1 ; переход на становку флага EOF

inc si ; Увеличиваем счетчик

cmp byte ptr [di],10а ; Смотрим не пустая ли строка

je frd3 ; Если да, то переход

inc dx ; Увеличиваем адрес буфера

inc di ; Увеличиваем казатель начала буфера

jmp frd1 ; Чтение следующего символа

end1: mov EOF,1 ; Устанавливаем флаг конца файла

frd3: clc ; Сброс флага переноса

ret ; Выход

Fread endp

;┌─────────────────────────┐

;│ Процедура записи в файл │

;└─────────────────────────┘

Fwrite procа near

mov bx,dest ; Заносим в BX дескриптор

lea dx,cod ; Заносим в DX записываемый код

mov cx,2 ; Число байт для записи

mov ah,40h ; Функция записи в файл

int 21h ; Вызов прерывания DOS

jnc ok4 ; Переход, если нет ошибки

Wrt error10 ; Вывод сообщения об ошибке

ok4:а ret ; Выход

Fwrite endp

;┌──────────────────────────┐

;│ Процедура даления файла │

;└──────────────────────────┘

Fdelа procа near

mov dx,path2 ; Путь к даляемому файлу

mov ah,41h ; Функция даления файла

int 21h ; Вызов прерывания DOS

jnc ok5 ; Переход, если нет ошибки

lea dx,defaul2 ; Пробуем далить OUT.COM

mov ah,41h ; Функция даления файла

int 21h ; Вызов прерывания DOS

jnc ok5 ; Переход, если нет ошибки

Wrt error11 ; Вывод сообщения об ошибке

ok5:а ret ; Выход

defaul2 db 'OUT.COM',0

Fdelа endp

;┌────────────────────────────────┐

;│ Процедура кодирования операции │

;└────────────────────────────────┘

Coding procа near

inc di ; величиваем казатель в массиве

mov si,di ; Заносим в SI адрес первого операнда

mov cod,0 ; Обнулаяем код

mov numbop,0 ; Номер операнда - первый

mov al,',' ; Будем искать разделитель операндов

mov cx,strlen ; В CX заносим длину строки

sub cx,4 ; Вычитаем длину ADD+пробел

repne scasb ; Начало поиска

je cod1 ; Переход, если разделитель найден

Wrt error07 ; Выдаем сообщение об ошибке

callа WrtStr ; Выводим адрес ошибочной строки

mov was_error,1 ; Устанавливаем флаг ошибки

ret ; Выход

cod1: mov second,di ; В second адрес второго операнда

dec di ; Смещаем казатель

dec di ; на конец первого операнда

cod2: mov dx,di ; Запоминаем адрес конца первого оп.

sub dx,si ; Выч. из адреса конца адрес начала

inc dx ; величиваем на 1

cmp dx,2 ; Смотрим длину первого операнда

je cod3 ; Если она равна 2, операнд - регистр

ja cod8 ; Если больше, операнд - память

Wrt error08 ; Выдаем сообщение об ошибке

callа WrtStr ; Выводим адрес ошибочной строки

mov was_error,1 ; Устанавливаем флаг ошибки

ret ; Выход

; --------------------------------------; операнд - регистр

cod3: mov dx,16 ; Всего 16 регистров. DX - счетчик

lea di,Rtable ; Загружаем адрес таблицы регистров

newreg: mov cx,2 ; Сравниваем два символа

rep cmpsb ; Начало сравнения

je regfound ; Переход, если регистр найден

inc di ; Увеличиваем смещение в таблице на 1

inc di ; Увеличиваем смещение в таблице на 1

dec si ; Указатель на начало перв. операнда

dec dx ; Уменьшаем счетчик на 1

jnz newreg ; Если еще не все регистры, переход

Wrt error08 ; Если регистр не найден - ошибка

callа WrtStr ; Выводим адрес ошибочной строки

mov was_error,1 ; Устанавливаем флаг ошибки

ret ; Выход

regfound:

mov ah,[di] ; Запоминаем код регистра

cmp numbop,0 ; Если это первый операнд

je cod7 ; То переход на становку d-бита

cmp typeop,1 ; Иначе это второй операнд

je cod4 ; Переход, если первый оп. имеет тип m

xor al,al ; Иначе оба операнда регистры

mov bx,cod ; Заносим в BX код операции

mov bh,ah ; Заносим в BH код регистра

and bx,0101h ; Сравниваем w-биты

cmp bh,bl ; Обоих операндов

je cod5 ; Если они равны, то переход

Wrt error09 ; Иначе ошибка - несоответствие типов

callа WrtStr ; Выводим адрес ошибочной строки

mov was_error,1 ; Устанавливаем флаг ошибки

ret ; Выход

cod4: mov al,ah ; Заносим в AL код команды

and al,01h ; Устанавливаем в 1 w-бит

and ah,00b ; Установка битов в поле reg

jmp cod6 ; Переход на следующий операнд

cod5: mov cl,3 ; Будем сдвигать на 3 бита вправо

shr ah,cl ; Сдвигаем код регистра в поле r/m

or ah,0c0h ; Установка поля mod в 11

; (т.е. биты r/m определяют регистр)

cod6: or cod,ax ; Накладка становленных битов на код

inc numbop ; Берем второй операнд

mov typeop,0 ; Устанавливаем тип операнда r

jmp cod11 ; Переход далее

cod7: mov al,02h ; Установка бита направления (d-бит)

or al,ah ; Накладываем на код

and ax,0011b ; становка битов в поле reg и r/m

mov cod,ax ; Заносим полученное в готовый код

inc numbop ; Увеличиваем номер операнда

mov typeop,0 ; Устанавливаем тип операнда r

jmp short cod11 ; Переход далее

;---------------------------------------; операнд - память

cod8: cmp numbop,0 ; Первый операнд?

je cod9 ; Если да - переход

cmp typeop,1 ; Тип операнда m?

jne cod9 ; Если нет - переход

Wrt error10 ; Иначе ошибка: оба операнда - память

callа WrtStr ; Выводим номер ошибочной строки

mov was_error,1 ; Устанавливаем флаг ошибки

ret ; Выход

cod9: cmp byte ptr [si],'[' ; Операнд начинается со скобки?

jne cod10 ; Если нет - переход на ошибку

cmp byte ptr [di],']' ; Операнд заканчивается скобкой?

jne cod10 ; Если нет - переход на ошибку

inc si ; Пропускаем скобку

dec di ; Отодвигаем казатель назад от скобки

mov dx,di ; Заносим в DX конец операнда

sub dx,si ; Вычитаем из конца начало строки

inc dx ; Увеличиваем на 1

; Т.о. в DX - длина операнда

; --------- Далее идет становка полей mod и r/m ---------------------------

mov bx,7 ; Всего 7 типов адресации памяти

lea di,ExTabl ; Адрес таблицы способов адресации

rm1:а pushа si ; Запоминаем адрес начала операнда

mov cl,[di] ; Заносим в CL длину операнда

xor ch,ch ; Обнуляем CH

inc di ; Двигаем казатель в ExTabl

cmp cx,dx ; Сравниваем длины операндов

jne rm2 ; Переход если не равны

rep cmpsb ; Иначе сравниваем на соответствие

je rm3 ; Переход если равны

rm2:а inc di ; Двигаем казатель в ExTabl на 1

add di,cx ; Теперь сдвигаем его на 5

pop si ; Восст. адрес начала операнда

dec bx ; Уменьшаем счетчик вариантов

jnz rm1 ; Если он не равен нулю - переход

Wrt error08 ; Если счетчик равен 0, соответствий

callа WrtStr ; не найдено, значит ошибка в операнде

mov was_error,1 ; Устанавливаем флаг ошибки

ret ; Выход

rm3:а pop si ; Восст. адрес начала операнда

mov ah,[di] ; Заносим в AH код операции

xor al,al ; Обнуляем AL

or cod,ax ; Накладываем на код код операции

inc numbop ; Увеличиваем номер операнда

mov typeop,1 ; Устанавливаем тип операнда m

jmp cod11 ; Переход дальше

cod10:

Wrt error08 ; Выводим сообщение об ошибке

callа WrtStr ; Выводим ошибочную строку

mov was_error,1 ; Устанавливаем флаг ошибки

ret

cod11: cmp numbop,1 ; Это второй операнд?

je cod12 ; Если да - переход

ret ; Иначе выход

cod12: mov di,second ; Заносим в DI адрес второго операнда

mov si,di ; А также и в SI

mov cx,strlen ; Заносим в CX длину операнда

sub cx,4 ; Уменьшаем на 4

cod13: mov al,[di] ; Смотрим содержимое операнда

cmp al,' ' ; Пробел?

je cod14 ; Если да, то переход

cmp al,';' ; Коментарий?

je cod14 ; Если да, то переход

cmp al,13 ; Новая строка?

je cod14 ; Если да, то переход

inc di ; Увеличиваем адрес

loopа cod13 ; Повторяем цикл

cod14: dec di ; Уменьшаем адрес

jmp cod2 ; Переход

Coding endp

about db 13,10,'Транслятор команды ADD. (c) 1997, БГУИР, гр.410703, '

db 'Валасевич Сергей.',13,10,'$'

error01 db 'Формат запуска: ADD исходный_файл выходной_файл',13,10,'$'

error02 db 13,10,'Не задан выходной файл',13,10,7,'$'

error03 db 13,10,'Ошибка открытия входного файла',13,10,7,'$'

error04 db 13,10,'Ошибка создания выходного файла',13,10,7,'$'

error05 db 13,10,'Ошибка чтения входного файла',13,10,7,'$'

error06 db 13,10,'Неизвестная команда в строке: $'

error07 db 13,10,'Отсутствует второй операнд в строке: $'

error08 db 13,10,'Неверный операнд в строке: $'

error09 db 13,10,'Несоответствие типов операндов в строке $'

error10 db 13,10,'Ошибка записи в выходной файл',13,10,7,'$'

error11 db 13,10,'Ошибка даления выходного файла',13,10,7,'$'

mes1а db 13,10,'$'

mes2а db 13,10,'Трансляция завершена спешно$'

mes3а db 13,10,'Обработано строк: $'

bellа db 7,'$'

bufferа dbа 1024 dup (32) ; Буфер для считывания данных

command db 'add' ; Транслируемая команда

path1 dw 0 ; Адрес строки входного файла

path2 dw 0 ; Адрес строки выходного файла

source dw 0 ; Обработчик входного файла

destа dw 0 ; Обработчик выходного файла

; 00reg00w

Rtable db 'ax',1 ; 1b

db 'bx',25 ; 11001b

db 'cx',9 ; 1001b

db 'dx',17 ; 11b

db 'si',49 ; 00111b

db 'di',57 ; 00001b

db 'bp',41 ; 00101001b

db 'sp',33 ; 0011b

db 'al',0 ; b

db 'ah',32 ; 001b

db 'bl',24 ; 11b

db 'bh',56 ; 00b

db 'cl',8 ; 1b

db 'ch',40 ; 00101b

db 'dl',16 ; 1b

db 'dh',48 ; 0011b

;modr/m

ExTabl db 5,'bx+si',0 ; b

db 5,'bx+di',1 ; 1b

db 5,'bp+si',2 ; 10b

db 5,'bp+di',3 ; 11b

db 2,'si',4 ; 100b

db 2,'di',5 ; 101b

db 2,'bx',7 ; b

string db 0 ; Номер текущей строки

strlen dw 0 ; Длина текущей строки

EOF db 0 ; Флаг конца файла (1-конец достигнут, 2-нет)

was_error db 0 ; Флаг ошибки последней операции (1-была, 2-нет)

numbop db 0 ; Номер операнда (0-первый, 1-второй)

typeop db 0 ; Тип операнда (0-регистр, 1-память)

cod dw 0 ; Записываемый код

second dw 0 ; Адрес начала второго операнда

end begin


;╔══════════════════════════════════════════════════════════════════╗

;║ ТРАНСЛЯЦИЯ ВСЕХ МОДИФИКАЦИЙ КОМАНДЫ CMP ║

;╚══════════════════════════════════════════════════════════════════╝

.MODEL TINY

.CODE

JUMPS

ORG 100h

begin:

jmp general

Wrt macro string

mov ah,9 ; Функция вывода строки

lea dx,string ; Загружаем адрес строки

int 21h ; Вызов прерывания DOS

endm

;┌──────────────────────────────┐

;│ Основная процедура программы │

;└──────────────────────────────┘

general proc near

push cs ; Все сегментры к сегменту кода

push cs

push cs

pop ds

pop es

pop ss а; (необходимо для строковых операций)

Wrt autor ; Вывод информации о программе

; Начинаем разбор строки параметров

mov cl,ds:[80h] ; Получаем длину строки параметров

sub ch,ch ; Обнуляем ch

cmp cx,2 ; Смотрим длину строки параметров

jb source_error ; Если она меньше двух - нет вх.файла

mov di,82h ; Заносим в DI адрес начала поиска

аmov Addr1,di ; Запоминаем адрес входного файла

mov al,' ' ; Искать будем до первого пробела

repne scasb ; Запускаем цикл поиска

jne dest_error ; Если не нашли значет нет вых. файла

mov byte ptr [di-1],0 ; Приводим к формату ASCIIZ

mov Addr2,di ; Запоминаем адрес выходного файла

mov cl,ds:[80h] ; Заносим в cl длину строки поиска

sub ch,ch ; Обнуляем ch

mov al,13 ; Искать будем до символа CR

repne scasb ; Запуск цикла поиска

jne dest_error ; Если не нашли значет нет вых. файла

mov byte ptr [di-1],0 ; Приводим к формату ASCIIZ

call Fopen ; Открываем входной файл

jc open_source_error ; Если ошибка, выдаем сообщение

call Fcreate ; Создаем выходной файл

jc create_dest_error ; Если ошибка, выдаем сообщение

gen1: call Fread ; Считываем очередную строку из файла

jc read_error ; Переход если ошибка

cmp flag_eof,1 ; Смотрим признак конца файла

jne gen2 ; Если не конец, продолжаем

cmp si,0 ; Проверяем длину строки

jne gen2 ; Если не 0 символов продолжаем

jmpа read_error ; Иначе выводим сообщение об ошибке

gen2: inc string ; величиваем счетчик строк

mov strlen,si ; Запоминаем длину строки

call DelSpc ; Вызываем процедуру даления пробелов

cmp strlen,2 ; Если длина строки 2 символа, то

je gen1 ; переходим на чтение следующей

lea di,buffer ; Загружаем адрес строки

cmp byte ptr [di],';' ; Если первый символ строки ; то

je gen1 ; переходим на чтение следующей

lea si,command ; Будем искать строку CMP

mov cx,3 ; Длина искомой строки 3 символа

repe cmpsb ; Начинаем поиск

je gen3 ; Переход, если CMP найдена

wrt error06 ; Вывод сообщения об ошибке

call WrtStr ; Вывод ошбочной строки

mov flag_err,1 ; станавливаем флаг ошибки

jmp gen1 ; Переход на чтение следующей строки

gen3: call Coding

cmp flag_err,0

jne gen1

call Fwrite

jncа gen1

ret

gen4: mov bx,dest ; Если трансляция проведена успешно

call Fclose ; Закрываем выходной файл

Wrt m2 ; Вывод сообщения о завершении

Wrt m3 ; Вывод сообщения о строках

call WrtStr ; Вывод числа обработаных строк

Wrt m1 ; Вывод CR,LF

ret ; ВЫХОД В DOS

; Далее располагаются метки перехода по различным ошибкам

source_error:

Wrt error01

ret

dest_error:

Wrt error02

ret

open_source_error:

Wrt error03

ret

create_dest_error:

Wrt error04

ret

read_error:

cmp flag_eof,1 ; Смотрим был ли конец файла

je skip_err_message ; Если да, то это не ошибка

Wrt error05 ; Иначе выводим сообщение об ошибке

mov flag_err,1 ; станавливаем флаг ошибки

skip_err_message:

mov bx,source ; Заносим дескриптор выходного файла

call Fclose ; Закрываем выходной файл

cmp flag_err,0 ; Смотрим флаг ошибки

je gen4 ; Если ошибок нет, то переход

call Fdel ; Иначе даляем выходной файл

Wrt m1 ; Вывод CR,LF

Wrt bell ; Вывод сигнала

ret

general endp

;┌──────────────────────────────────────────────────────┐

; Переводит значение регистра AX в десятичный формата │

;└──────────────────────────────────────────────────────┘

Decimal proc near

call clear ; Очищаем строку вывода

mov cx,0010 ; Заносим в CX делитель

lea si,outstr+4 ; казатель на конец строки

b20: cmp ax,0010 ; Сравниваем AX с 10

jb short b30 ; Переход, если меньше

xor dx,dx ; Обнуляем DX

div cx ; Делем AX на CX

or dl,30h ; Добавляем 48, чтобы получить 1

mov [si],dl ; Заносим в выходную строку

dec si ; Движемся влево

jmp short b20 ; Переход на следующий символ

b30: or al,30h ; Добавляем 48, чтобы получить 1

mov [si],al ; Заносим в выходную строку

ret

; Вспомогательная процедура. Очищает строку outstr (забивает нулями)

clear proc near

lea si,outstr ; Загружаем адрес выходной строки

mov cl,48 ; 48 - символ нуля

mov [si],cl ; Забиваем нулями символы

mov [si+1],cl

mov [si+2],cl

mov [si+3],cl

mov [si+4],cl

ret ; Выход

clear endp

outstrа db ' $'

Decimal endp

;┌──────────────────────────────┐

;│ Процедура вывода числа строк │

;└──────────────────────────────┘

WrtStrа proc near

xor ax,ax ; Обнуление регистра AX

mov al,string ; В AL число обработанных строк

call Decimal ; Преобразуем в десятичный формат

Wrt outstr ; Выводим на экран

ret ; Выход

WrtStrа endp

;┌─────────────────────────────┐

;│ Процедура даления пробелов │

;└─────────────────────────────┘

DelSpcа proc near

cld ; станавливаем флаг направления

lea si,buffer ; Заносим в SI адрес буфера

mov di,si ; Дублируем в DI

mov cx,strlen ; В CX длина считанной строки

xor bx,bx ; Обнуляем BX

mov dl,1 ; словие цикла

del1: lodsb ; Загружаем в AL один байт

cmp al,65 ; A?

jb del2 ; Переход если меньше

cmp al,90 ; Z?

ja del2 ; Переход если больше

add al,32 а; Иначе перевод F-f

xor dl,dl ; Обнуляем DL

jmp del4 ; Переход на запись символа

del2: cmp al,' ' ; Пробел?

je del3 ; Если да, то переход

xor dl,dl ; Обнуляем DL

jmp del4 ; Переход на запись символа

del3: cmp dl,1 ; DL=1?

je del5 ; Если да, то переход

mov dl,1 ; Заносим в DL 1

del4: stosb ; Запись символа в строку

inc bx ; величиваем счетчик символов

del5: loop del1 ; Цикл

mov strlen,bx а; Заносим длину преобразованной строки

ret ; Выход

DelSpcа endp

;┌──────────────────────────┐

;│ Процедура открытия файла │

;└──────────────────────────┘

Fopen proc near

mov ah,3dh ; Функция открытия файла

xor al,al ; Открываем на чтение (AL=0)

mov dx,Addr1 ; Адрес ASCIIZ строки файла

int 21h ; Вызов прерывания DOS

jnc ok1 ; Переход, если открытие спешно

stc ; становка флага переноса

ret ; Выход

ok1: mov source,ax ; Запоминаем дескриптор файла

ret ; Выход

Fopen endp

;┌──────────────────────────┐

;│ Процедура создания файла │

;└──────────────────────────┘

Fcreate proc near

mov ah,3ch ; Функция создания файла

xor cx,cx ; Заносим атрибут файла в CX

mov dx,Addr2 ; Адрес ASCIIZ строки файла

int 21h ; Вызов прерывания DOS

jnc ok2 ; Переход, если файл создан спешно

mov ah,3ch ; Если выходной файл не задан

xor cx,cx ; станавливаем по молчанию

lea dx,default ; Имя OUT.COM

int 21h ; Пытаемся создать файл

jnc ok2 ; Если получилось - на выход

stc ; становка флага переноса

ret ; Выход

ok2: mov dest,ax ; Запоминаем дескриптор файла

ret ; Выход

default db 'OUT.COM',0

Fcreate endp

;┌──────────────────────────┐

;│ Процедура закрытия файла │

;└──────────────────────────┘

Fcloseа proc near

mov ah,3eh ; Функция закрытия файла

int 21h ; Вызов прерывания DOS

jnc ok3 ; Переход, если файл успешно закрыт

Wrt error05 ; Вывод сообщения об ошибке

ok3: ret ; Выход

Fcloseа endp

;┌────────────────────────┐

;│ Процедура чтения файла │

;└────────────────────────┘

Fread proc near

lea dx,buffer ; Загружаем адрес буфера

mov di,dx ; Запоминаем адрес начала буфера в DI

xor si,si ; Обнуляем SI

mov bx,source ; Заносим в BX дескриптор файла

mov cx,1 ; Число символов для чтения

frd1: mov ah,3fh ; Функция чтения из файла

int 21h ; Вызов прерывания DOS

jnc frd2 ; Переход, если нет ошибки

wrt error05 ; Вывод сообщения об ошибке

stc ; станавливаем флаг переноса

ret ; Выход

frd2: cmp ax,0 ; Если AX=0, то достигнут конец файла

je end1 ; переход на становку флага flag_eof

inc si ; величиваем счетчик

cmp byte ptr [di],10 ; Смотрим не пустая ли строка

je frd3 ; Если да, то переход

inc dx ; величиваем адрес буфера

inc di ; величиваем казатель начала буфера

jmp frd1 ; Чтение следующего символа

end1: mov flag_eof,1 ; станавливаем флаг конца файла

frd3: clc ; Сброс флага переноса

ret ; Выход

Fread endp

;┌─────────────────────────┐

;│ Процедура записи в файл │

;└─────────────────────────┘

Fwriteа proc near

mov ax,cmp_

or al,38h

mov cmp_,ax

mov bx,dest ; Заносим в BX дескриптор

lea dx,cmp_ ; Заносим в DX записываемый код

mov cx,2 ; Число байт для записи

mov ah,40h ; Функция записи в файл

int 21h ; Вызов прерывания DOS

jnc ok4 ; Переход, если нет ошибки

Wrt error10 ; Вывод сообщения об ошибке

ok4: ret ; Выход

Fwriteа endp

;┌──────────────────────────┐

;│ Процедура даления файла │

;└──────────────────────────┘

Fdel proc near

mov dx,Addr2 ; Путь к даляемому файлу

mov ah,41h ; Функция даления файла

int 21h ; Вызов прерывания DOS

jnc ok5 ; Переход, если нет ошибки

lea dx,defaul2 ; Пробуем далить OUT.COM

mov ah,41h ; Функция даления файла

int 21h ; Вызов прерывания DOS

jnc ok5 ; Переход, если нет ошибки

Wrt error11 ; Вывод сообщения об ошибке

ok5: ret ; Выход

defaul2 db 'OUT.COM',0

Fdel endp

;┌────────────────────────────────┐

;│ Процедура кодирования операции │

;└────────────────────────────────┘

Codingа proc near

inc di ; величиваем указатель в массиве

mov si,di ; Заносим в SI адрес первого операнда

mov cmp_,0 ; Обнулаяем код

mov numbop,0 ; Номер операнда - первый

mov al,',' ; Будем искать разделитель операндов

mov cx,strlen ; В CX заносим длину строки

sub cx,4 ; Вычитаем длину CMP+пробел

repne scasb ; Начало поиска

je cmp_1 ; Переход, если разделитель найден

Wrt error07 ; Выдаем сообщение об ошибке

call WrtStr ; Выводим адрес ошибочной строки

mov flag_err,1 ; станавливаем флаг ошибки

ret ; Выход

cmp_1: mov addr2,di ; В addr2 адрес второго операнда

dec di ; Смещаем казатель

dec di ; на конец первого операнда

cmp_2: mov dx,di ; Запоминаем адрес конца первого оп.

sub dx,si ; Выч. из адреса конца адрес начала

inc dx ; величиваем на 1

cmp dx,2 ; Смотрим длину первого операнда

je cmp_3 ; Если она равна 2, операнд - регистр

ja cmp_8 ; Если больше, операнд - память

Wrt error08 ; Выдаем сообщение об ошибке

call WrtStr ; Выводим адрес ошибочной строки

mov flag_err,1 ; станавливаем флаг ошибки

ret ; Выход

; --------------------------------------; операнд - регистр

cmp_3: mov dx,16 ; Всего 16 регистров. DX - счетчик

lea di,RegTabl ; Загружаем адрес таблицы регистров

newreg: mov cx,2 ; Сравниваем два символа

rep cmpsb ; Начало сравнения

je regfound ; Переход, если регистр найден

inc di ; величиваем смещение в таблице на 1

inc di ; величиваем смещение в таблице на 1

dec si ; казатель на начало перв. операнда

dec dx ; меньшаем счетчик на 1

jnz newreg ; Если еще не все регистры, переход

Wrt error08 ; Если регистр не найден - ошибка

call WrtStrа ; Выводим адрес ошибочной строки

mov flag_err,1 ; станавливаем флаг ошибки

ret ; Выход

regfound:

mov ah,[di] ; Запоминаем код регистра

cmp аnumbop,0 ; Если это первый операнд

je cmp_7 ; То переход на становку d-бита

cmp typeop,1 ; Иначе это второй операнд

je cmp_4 ; Переход, если первый оп. имеет тип m

xor al,al ; Иначе оба операнда регистры

mov bx,cmp_ ; Заносим в BX код операции

mov bh,ah ; Заносим в BH код регистра

and bx,0101h ; Сравниваем w-биты

cmp bh,bl ; Обоих операндов

je cmp_5 ; Если они равны, то переход

Wrt error09 ; Иначе ошибка - несоответствие типов

call WrtStr ; Выводим адрес ошибочной строки

mov flag_err,1 ; станавливаем флаг ошибки

ret ; Выход

cmp_4: mov al,ah ; Заносим в AL код команды

and al,01h ; станавливаем в 1 w-бит

and ah,00b ; становка битов в поле reg

jmp cmp_6 ; Переход на следующий операнд

cmp_5: mov cl,3 ; Будем сдвигать на 3 бита вправо

shr ah,cl ; Сдвигаем код регистра в поле r/m

or ah,0c0h ; становка поля mod в 11

; (т.е. биты r/m определяют регистр)

cmp_6: or cmp_,ax ; Накладка становленных битов на код

inc numbop ; Берем второй операнд

mov typeop,0 ; станавливаем тип операнда r

jmp cmp_11 ; Переход далее

cmp_7: mov al,02h ; становка бита направления (d-бит)

or al,ah ; Накладываем на код

and ax,0011b ; становка битов в поле reg и r/m

mov cmp_,ax ; Заносим полученное в готовый код

inc numbop ; величиваем номер операнда

mov typeop,0 ; станавливаем тип операнда r

jmp short cmp_11 ; Переход далее

;---------------------------------------; операнд - память

cmp_8: cmp numbop,0 ; Первый операнд?

je cmp_9 ; Если да - переход

cmp typeop,1 ; Тип операнда m?

jne cmp_9 ; Если нет - переход

Wrt error10 ; Иначе ошибка: оба операнда - память

call WrtStr ; Выводим номер ошибочной строки

mov flag_err,1 ; станавливаем флаг ошибки

ret ; Выход

cmp_9: cmp byte ptr [si],'[' ; Операнд начинается со скобки?

jne cmp_10 ; Если нет - переход на ошибку

cmp byte ptr [di],']' ; Операнд заканчивается скобкой?

jne cmp_10 ; Если нет - переход на ошибку

inc si ; Пропускаем скобку

dec di ; Отодвигаем казатель назад от скобки

mov dx,di ; Заносим в DX конец операнда

sub dx,si ; Вычитаем из конца начало строки

inc dx ; величиваем на 1

; Т.о. в DX - длина операнда

; --------- Далее идет становка полей mod и r/m ---------------------------

mov bx,7 ; Всего 7 типов адресации памяти

lea di,MemTabl ; Адрес таблицы способов адресации

rm1: push si ; Запоминаем адрес начала операнда

mov cl,[di] ; Заносим в CL длину операнда

xor ch,ch ; Обнуляем CH

inc di ; Двигаем казатель в MemTab

cmp cx,dx ; Сравниваем длины операндов

jne rm2 ; Переход если не равны

rep cmpsb ; Иначе сравниваем на соответствие

je rm3 ; Переход если равны

rm2: inc di ; Двигаем казатель в MemTabl на 1

add di,cx ; Теперь сдвигаем его на 5

pop si ; Восст. адрес начала операнда

dec bx ; меньшаем счетчик вариантов

jnz rm1 ; Если он не равен нулю - переход

Wrt error08 ; Если счетчик равен 0, а соответствий

call WrtStr ; не найдено, значит ошибка в операнде

mov flag_err,1 ; станавливаем флаг ошибки

ret ; Выход

cmp_11:а cmp numbop,1

je cmp_12

ret

rm3: pop si ; Восст. адрес начала операнда

mov typeop,1 ; станавливаем тип операнда m

jmp cmp_11 ; Переход дальше

cmp_10:

Wrt error08 ; Выводим сообщение об ошибке

call WrtStr ; Выводим ошибочную строку

mov flag_err,1 ; станавливаем флаг ошибки

ret

cmp_12:а mov di,addr2 ; Заносим в DI адрес второго операнда

mov si,di ; А также и в SI

mov cx,strlen ; Заносим в CX длину операнда

sub cx,4 а; меньшаем на 4

cmp_13:а mov al,[di] ; Смотрим содержимое операнда

cmp al,' ' ; Пробел?

je cmp_14 ; Если да, то переход

cmp al,';' ; Коментарий?

je cmp_14 ; Если да, то переход

cmp al,13 ; Новая строка?

je cmp_14 ; Если да, то переход

inc di ; величиваем адрес

loop cmp_13 ; Повторяем цикл

cmp_14:а dec di ; меньшаем адрес

jmp cmp_2 ; Переход

Codingа endp

Autor db 13,10,'Транслятор команды CMP. (c) 1997, БГУИР, гр.410703, '

db 'Коровинский Сергей.',13,10,'$'

error01 db 'Формат запуска: CMP исходный_файл выходной_файл',13,10,'$'

error02 db 13,10,'Не задан выходной файл',13,10,7,'$'

error03 db 13,10,'Ошибка открытия входного файла',13,10,7,'$'

error04 db 13,10,'Ошибка создания выходного файла',13,10,7,'$'

error05 db 13,10,'Ошибка чтения входного файла',13,10,7,'$'

error06 db 13,10,'Неизвестная команда в строке: $'

error07 db 13,10,'Отсутствует второй операнд в строке: $'

error08 db 13,10,'Неверный операнд в строке: $'

error09 db 13,10,'Несоответствие типов операндов в строке $'

error10 db 13,10,'Ошибка записи в выходной файл',13,10,7,'$'

error11 db 13,10,'Ошибка даления выходного файла',13,10,7,'$'

m1 db 13,10,'$'

m2 db 13,10,'Трансляция завершена спешно$'

m3 db 13,10,'Обработано строк: $'

bell db 7,'$'

bufferа db 1024 dup (32) ; Буфер для считывания данных

command db 'cmp' ; Транслируемая команда

Addr1 dw 0 ; Адрес строки входного файла

Addr2 dw 0 ; Адрес строки выходного файла

sourceа dw 0 ; Обработчик входного файла

dest dw 0 ; Обработчик выходного файла

; 00reg00w

RegTabl db 'ax',1 ; 1b

db 'bx',25 ; 11001b

db 'cx',9 ; 1001b

db 'dx',17 ; 11b

db 'si',49 ; 00111b

db 'di',57 ; 00001b

db 'bp',41 ; 00101001b

db 'sp',33 ; 0011b

db 'al',0 ; b

db 'ah',32 ; 001b

db 'bl',24 ; 11b

db 'bh',56 ; 00b

db 'cl',8 ; 1b

db 'ch',40 ; 00101b

db 'dl',16 ; 1b

db 'dh',48 ; 0011b

; modr/m

MemTabl db 5,'bx+si',0 ; b

db 5,'bx+di',1 ; 1b

db 5,'bp+si',2 ; 10b

db 5,'bp+di',3 ; 11b

db 2,'si',4 ; 100b

db 2,'di',5 ; 101b

db 2,'bx',7 ; b

stringа db 0 ; Номер текущей строки

strlenа dw 0 ; Длина текущей строки

flag_eof db 0 ; Флаг конца файла (1-конец достигнут, 2-нет)

flag_err db 0 ; Флаг ошибки последней операции (1-была, 2-нет)

numbopа db 0 ; Номер операнда (0-первый, 1-второй)

typeopа db 0 ; Тип операнда (0-регистр, 1-память)

cmp_ dw 0 ; Записываемый код

addr2 dw 0 ; Адрес начала второго операнда

end begin


1. Анализ технического задания

В данном курсовом проекте необходимо разработать программу н языке Ассемблер для МП Intel 8086 реализующую функции транслятора всеха модификаций команды ADD. Программа должна правильно распознавать тип адресации (например регистр-регистр, регистр-память, память-регистр), иметь

подпрограммы обработки ошибок трансляции, выводить информацию о процессе трансляции и ошибках на экран дисплея. Команды для трансляции должны

быть оформлены в виде текстового файла, находящегося в одном каталоге с

программой-транслятором. При анализе команд трансляторома также должны

правильно обрабатываться:

- пустые строки

- строки с начальными и конечными пробелами

- строки-комментарии

- прописные и заглавные буквы

- ошибочные операторы

Результатом работы программы-транслятора должен быть выходной файл,

содержащий машинные коды оттранслированных команд. Входнойа и выходной

файлы должны задаваться в командной строке запуск программы-транслятора в виде параметров.

Для разработки транслятора понадобятся некоторые сведения о структуре команды ADD, обозначении регистров и способах адресации.

Объектный код команды ADD имеет следующий вид:

d w mod reg r/m

───┬── ┬ ┬ ─┬─ ─┬─ ─┬─

а │ а └──── казатель регистр/память (3 бита)

а │ а └──────── Тип регистра (3 бита)

│ └──────────── Тип адресации регистр/память (2 бита)

│ └─────────────── Размер регистра (0-байт, 1-слово)

а └───────────────── Бит направления передачи

└───────────────────── Код операции

Регистры микропроцессора Intel 8086 кодируются следующим образом:

┌──────────────┬────────────┬───────────┐

│ Код регистра │ w=0 │ w=1 │

├──────────────┼────────────┼───────────┤

│ │ AL │ AX │

│ 001 │ CL │ CX │

│ 010 │ DL │ DX │

│ 011 │ BL │ BX │

│ 100 │ AH │ SP │

│ 101 │ CHа │ BP │

│ 110 │ DH │ SI │

│ │ BH │ DI │

└──────────────┴────────────┴───────────┘

Биты MOD могут принимать следующие значения:

00 - биты r/m дают абсолютный адрес, байт смещения

(относительный адрес) отсутствует

01 - биты r/m дают абсолютный адрес памяти и имеется

один байт смещения

10 - биты r/m дают абсолютный адрес и имеется два

байта смещения

11 - биты r/m определяют регистр. Бит w (в байте кода

операции) определяет ссылку на восьми- или

шестнадцатибитовый регистр

Биты R/M определяют способ адресации следующим образом:

┌─────┬────────┐

│ R/M │ mod=00 │

├─────┼────────┤

│ │ BX+SIа │

│ 001 │ BX+DIа │

│ 010 │ BP+SIа │

│ 011 │ BP+DIа │

│ 100 SI │

│ 101 DI │

│ 110 │ Direct │

│ BX │

└─────┴────────┘


2. Разработка алгоритма

Разработаем алгоритм для программы-транслятора. Послеа запуск на

выполнение программа проверяет параметры командной строки. Ва командной

строке должны быть заданы входной и выходной файлы для трансляции. При

отсутствии входного файла выдается сообщение об ошибке иа программ заканчивает свою работу. При отсутствии выходного файла по молчанию станавливается выходной файл с именем OUT.COM.

Далее идет открытие входного файла на чтение и выходного на запись.

Из входного файла считывается одна строка. Если это пустая строк или

строка-комментарий, то она игнорируется и программа считывает следующую

строку. Если в строке содержаться начальные или конечные пробелы, то они

даляются. Затем вся строка преобразуется к нижнему регистру.

Запускается поиск строки 'add'. Если строка найден анализируются

первый и второй операнды. Проверяется тип адресации, анализируются биты

mod, r/m, w, d, reg. В соответствии с этим кодируется машинная команда,

осуществляющая данную операцию. Если в обоих операндах не было ошибок,

то машинная команда записывается в выходной файл. Затем считывается следующая строка и так далее, пока не достигнут конец входного файла. После достижения конца файла смотрим на наличие ошибок трансляции. Если они

обнаружены, то выходной файл даляется. Если нет закрываем входной и выходной файлы и выдаем сообщение об спешной трансляции.


3. Разработка структуры данных

При работе программа-транслятор использует следующие переменные:

┌────────────┬────────────────────────────────────────────────────────┐

│ Переменная │ Описание (содержание) переменной │

├────────────┼────────────────────────────────────────────────────────┤

аbout │ Содержит информацию о программе и ее авторе │

error01 │ "Формат запуска: ADD исходный_файл выходной_файл" │

error02 │ "Не задан выходной файл" │

error03 │ "Ошибка открытия входного файла" │

error04 │ "Ошибка создания выходного файла" │

error05 │ "Ошибка чтения входного файла" │

error06 │ "Неизвестная команда в строке" │

error07 │ "Отсутствует второй операнд в строке" │

error08 │ "Неверный операнд в строке" │

error09 │ "Несоответствие типов операндов в строке" │

error10 │ "Ошибка записи в выходной файл" │

error11 │ "Ошибка даления выходного файла" │

mes1 │ Содержит символы перевод строки, возврат каретки │

mes2 │ "Трансляция завершена спешно" │

mes3 │ "Обработано строк" │

bell │ Содержит правляющий символ N7 (звуковой сигнал) │

buffer │ В этот буфер заносится информация из входного файл │

command │ Содержит транслируемую команду (ADD) │

path1 │ Полный путь и имя входного файл │

path2 │ Полный путь и имя выходного файл │

source │ Обработчик (дескриптор) входного файл │

dest │ Обработчик (дескриптор) выходного файл │

Rtable │ Таблица мнемонических обозначений регистров и их коды │

ExTabl │ Тоже самое, но при адресации памяти │

string │ Номер текущей строки │

strlen │ Длина текущей строки │

EOF │ Флаг конца файла (1-конец достигнут, 2-нет) │

was_error │ Флаг ошибки последней операции (1-была, 2-нет) │

numbop │ Номер операнда (0-первый, 1-второй) │

typeop │ Тип операнда (0-регистр, 1-память) │

cod │ Записываемый код │

second │ Адрес начала второго операнд │

│ │ │

└────────────┴────────────────────────────────────────────────────────┘

Процедуры, использующиеся в данной программе:

┌────────────┬────────────────────────────────────────────────────────┐

│ Название │ Описание процедуры │

├────────────┼────────────────────────────────────────────────────────┤

│ Wrt │ Макрос вывода на экран строки stirng │

│ General │ Основная процедура программы │

│ Decimal │ Переводит значение регистра AX в десятичный формат │

│ WrtStr │ Процедура вывода числа строк │

│ DelSpc │ Процедура даления пробелов │

│ Fopen │ Процедура открытия файл │

│ Fcreate │ Процедура создания файл │

│ Fclose │ Процедура закрытия файл │

│ Fread │ Процедура чтения файл │

│ Fwrite │ Процедура записи в файл │

│ Fdel │ Процедура даления файл │

│ Coding │ Процедура кодирования операции │

│ │ │

└────────────┴────────────────────────────────────────────────────────┘


4. Кодирование алгоритма

Запишем разработанный нами алгоритм в мнемокоде на языке Ассемблер.

Основным прерыванием, используемым в программе, является прерывания INT 21H (DOS Functions). В программе использованы следующие функции

данного прерывания:

AH=9 - Вывод текстовой строки на экран дисплея

AH=3Dh - Открытие файла

AH=3Ch - Создание файла

AH=3Eh - Закрытие файла

AH=3Fh - Чтение из файла

AH=40h - Запись в файл

AH=41h - Удаление файла

Далее располагается текст программы-транслятора на языке Ассемблер


5. Тестирование и отладка

программы

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

специальный входной файл, содержащий максимально возможное число затрудняющих моментов: пустые строки, строки коментарии (в начале строки, после оператора и сдвинутые относительно левой границы), команды и операторы, анабранные в различных регистрах. Содержимое этого файл приведено

ниже.

; Тестовый файл для проверки трансляции команды ADD

add ax,bx ; Команда, набранная маленькими буквами, адресация r,r

ADD [BP+SI],BXа ; Команда, набранная большими буквами, адресация m,r

add [DI],CX ; Сочетание больших и маленьких букв, адресация m,r

; Комментарий

; Сдвинутый комментарий

add dx,[bp+di] ; Адресация r,m

; Конец тестового файла


Заключение

Итогом данной курсовой работы стала программа-транслятор, реализующая функцию трансляции команды МП Intel 8086 ADD. Программ соответствует всем требованиям, которые были поставлены в пункте 1, обладает

высоким быстродействием, не требовательна к объему свободнойа памяти и

дисковым ресурсам. В программе чтены все возможные ситуации, в которых

может возникнуть ошибка и предприняты попытки по странению большинства

из них.

В процессе выполнения курсового проекта мною были более широко изучены функции прерывания DOS 21h и приобретены навыкиа написания прог-

рамм-трансляторов.


Литература

1. Абель П. Язык Ассемблера для IBM PC и программирования

М.; Высшая Школа, 1992г.

2. Соловьев Г.H. Операционная система ЭВМ, Высшая школа, 1989г

3. Краковяк С. Основы организации и функционирования операционной

системы ЭВМ

4. Вишняков В.А., Петровский А.А. Системное обеспечение микроЭВМ

5. Hортон П. Персональный компьютер фирмы IBM и операционная система

MS-DOS

6. Финогенов К.Г. Самоучитель по системным функциям MS-DOS


[1]L*.FRM*.MAC
<

Б