Загрузить архив: | |
Файл: 240-0258.zip (20kb [zip], Скачиваний: 26) скачать |
Введение
Для написания пользователем программ на различных языках программи-
рования необходимо иметь средства их перевода в машинный язык.Это вы-
полняют специальные программы-переводчики, которые называются транслято-
рами.Трансляторы для микроЭВМ преобразуют исходную программу наодном
из языков программирования в некоторую стандартную форму, называемую
объектной программой. Существует три вида трансляторов: ассемблеры, ком-
пиляторы и интерпретаторы.
Транслятор, преобразующий программу, написанную на языке ассембле-
ра, в машинный код,называется ассемблером.При написании программы на
языке ассемблера программист использует мнемонические обозначения машин-
ных команд и адресов (имена и метки).В процессетрансляции ассемблер
заменяет все мнемонические обозначения (коды команд и имена) их двоичны-
ми кодами.Для сокращения текста при повторении идентичных частей прог-
раммы в отдельные языки ассемблера введены средства написания и обработ-
ки макрокоманд. Это позволяет программисту определить некоторую последо-
вательность команд как макроопределение, которое обрабатывается макроас-
семблером (макропроцессором). Последний представляет тексты макроопреде-
лений с соответствующимифактическимипараметрами макровызовавместо
макрокоманд в программе.
Простейший ассемблер является однопроходным и преобразует исходную
программу за один просмотр. Но при этом возникают трудности, связанные с
вычислением адресов имен,которые определены позже.Этого можноизбе-
жать, потребовав, чтобы все имена данных были объявлены заранее, а неоп-
ределенные адреса заносились в таблицу,в которую вводятся ссылкивпе-
ред. Эта таблица либо используется для модификации команды, либо загруз-
чиком, который может формировать данный адрес во время загрузки.Однако
это не всегда удобно,поэтому большинство ассемблеров выполняютвдва
прохода.
Основная идея двухпроходного ассемблера проста. На первомпроходе
все символы (имена, метки) собираются в таблицу символов с соответствую-
щими значениями адресов,на втором генерируется машиннаяпрограммана
основании построенной на первом проходе таблицы символов.
Если язык ассемблера включает средства макрорасширений, то макроп-
роцессор реализуется различными способами.Он может быть добавлен к ас-
семблеру как препроцессор для выполнения просмотра исходного текстапе-
ред первым проходом ассемблера.В результатепрепроцессированияполу-
чается программа на языке ассемблера,на содержащая макросов.При этом
тексты макроопределений, если они есть в исходной программе,сохраняют-
ся, а вместо макровызовов подставляются ассемблерные команды из макрооп-
ределений.Возможно также объединение макропроцессора с первым проходом
ассемблера, что сокращает время трансляции, но удлиняет текст ассемблера.
;█▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀█
;█ ----- ТРАНСЛЯЦИЯ ВСЕХ МОДИФИКАЦИЙ КОМАНДЫ ADD ----- █
;█▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄█
.MODEL TINY
.CODE
JUMPS
ORG 100h
begin:
jmp general
;┌──────────────────────────────────────┐
;│ Макрос вывода на экран строки stirng │
;└──────────────────────────────────────┘
Wrt macrostring
mov ah,9 ; Функция вывода строки
lea dx,string ; Загружаем адрес строки
int 21h ; Вызов прерывания DOS
endm
;┌──────────────────────────────┐
;│ Основная процедура программы │
;└──────────────────────────────┘
general procnear
pushcs ; Все
pushcs ; сегменты
pushcs ; приравниваем
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,' ' ; Искать будем до первого пробела
repnescasb ; Запускаем цикл поиска
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
repnescasb ; Запуск цикла поиска
jne dest_error ; Если не нашли значет нет вых. файла
mov byte ptr [di-1],0; Приводим к формату ASCIIZ
callFopen ; Открываем входной файл
jc open_source_error; Если ошибка, выдаем сообщение
callFcreate ; Создаем выходной файл
jc create_dest_error; Если ошибка, выдаем сообщение
gen1:callFread ; Считываем очередную строку из файла
jc read_error ; Переход если ошибка
cmp EOF,1 ; Смотрим признак конца файла
jne gen2 ; Если не конец, продолжаем
cmp si,0 ; Проверяем длину строки
jne gen2 ; Если не 0 символов продолжаем
jmp read_error ; Иначе выводим сообщение об ошибке
gen2:inc string ; Увеличиваем счетчик строк
mov strlen,si ; Запоминаем длину строки
callDelSpc ; Вызываем процедуру удаления пробелов
cmp strlen,2 ; Если длина строки 2 символа, то
je gen1 ; переходим на чтение следующей
lea di,buffer ; Загружаем адрес строки
cmp byte ptr [di],';'; Если первый символ строки ; то
je gen1 ; переходим на чтение следующей
lea si,command ; Будем искать строку ADD
mov cx,3 ; Длина искомой строки 3 символа
repecmpsb ; Начинаем поиск
je gen3 ; Переход, если ADD найдена
wrt error06 ; Вывод сообщения об ошибке
callWrtStr ; Вывод ошбочной строки
mov was_error,1 ; Устанавливаем флаг ошибки
jmp gen1 ; Переход на чтение следующей строки
gen3:callCoding
cmp was_error,0
jne gen1
callFwrite
jnc gen1
ret
gen4:mov bx,dest ; Если трансляция проведена успешно
callFclose ; Закрываем выходной файл
Wrt mes2 ; Вывод сообщения о завершении
Wrt mes3 ; Вывод сообщения о строках
callWrtStr ; Вывод числа обработаных строк
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 ; Заносим дескриптор выходного файла
callFclose ; Закрываем выходной файл
cmp was_error,0 ; Смотрим флаг ошибки
je gen4 ; Если ошибок нет, то переход
callFdel ; Иначе удаляем выходной файл
Wrt mes1 ; Вывод CR,LF
Wrt bell ; Выводсигнала
ret
general endp
;┌──────────────────────────────────────────────────────┐
;│Переводитзначениерегистра AX вдесятичныйформат │
;└──────────────────────────────────────────────────────┘
Decimal procnear
callclear ; Очищаемстрокувывода
mov cx,0010 ; Заносим в CX делитель
lea si,outstr+4 ; Указатель на конец строки
b20:cmp ax,0010 ; Сравниваем AX с 10
jb shortb30 ; Переход, если меньше
xor dx,dx ; Обнуляем DX
div cx ; Делем AX на CX
or dl,30h ; Добавляем 48, чтобы получить 1
mov [si],dl ; Заносим в выходную строку
dec si ; Движемся влево
jmp shortb20 ; Переход на следующий символ
b30:or al,30h ; Добавляем 48, чтобы получить 1
mov [si],al ; Заносим в выходную строку
ret
; Вспомогательная процедура. Очищает строку outstr (забивает нулями)
clearprocnear
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 ; Выход
clearendp
outstr db ' $'
Decimal endp
;┌──────────────────────────────┐
;│ Процедуравыводачисластрок │
;└──────────────────────────────┘
WrtStr procnear
xor ax,ax ; Обнулениерегистра AX
mov al,string ; В AL число обработанных строк
callDecimal ; Преобразуем в десятичный формат
Wrt outstr ; Выводим на экран
ret ; Выход
WrtStr endp
;┌─────────────────────────────┐
;│ Процедура удаления пробелов │
;└─────────────────────────────┘
DelSpc procnear
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:loopdel1 ; Цикл
mov strlen,bx ; Заносим длину преобразованной строки
ret ; Выход
DelSpc endp
;┌──────────────────────────┐
;│ Процедура открытия файла │
;└──────────────────────────┘
Fopenprocnear
mov ah,3dh ; Функция открытия файла
xor al,al ; Открываем на чтение (AL=0)
mov dx,path1 ; Адрес ASCIIZ строки файла
int 21h ; Вызов прерывания DOS
jnc ok1 ; Переход, если открытие успешно
stc ; Установка флага переноса
ret ; Выход
ok1:mov source,ax ; Запоминаем дескриптор файла
ret ; Выход
Fopenendp
;┌──────────────────────────┐
;│ Процедура создания файла │
;└──────────────────────────┘
Fcreate procnear
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 procnear
mov ah,3eh ; Функциязакрытияфайла
int 21h ; Вызов прерывания DOS
jnc ok3 ; Переход, если файл успешно закрыт
Wrt error05 ; Вывод сообщения об ошибке
ok3:ret ; Выход
Fclose endp
;┌────────────────────────┐
;│ Процедурачтенияфайла │
;└────────────────────────┘
Freadprocnear
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 ; Выход
Freadendp
;┌─────────────────────────┐
;│ Процедура записи в файл │
;└─────────────────────────┘
Fwrite procnear
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
;┌──────────────────────────┐
;│ Процедураудаленияфайла │
;└──────────────────────────┘
Fdelprocnear
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
Fdelendp
;┌────────────────────────────────┐
;│ Процедуракодированияоперации │
;└────────────────────────────────┘
Coding procnear
inc di ; Увеличиваемуказательвмассиве
mov si,di ; Заносим в SI адрес первого операнда
mov cod,0 ; Обнулаяем код
mov numbop,0 ; Номер операнда - первый
mov al,',' ; Будем искать разделитель операндов
mov cx,strlen ; В CX заносим длину строки
sub cx,4 ; Вычитаем длину ADD+пробел
repnescasb ; Начало поиска
je cod1 ; Переход, если разделитель найден
Wrt error07 ; Выдаем сообщение об ошибке
callWrtStr ; Выводим адрес ошибочной строки
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 ; Выдаем сообщение об ошибке
callWrtStr ; Выводим адрес ошибочной строки
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 ; Если регистр не найден - ошибка
callWrtStr ; Выводим адрес ошибочной строки
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 ; Иначе ошибка - несоответствие типов
callWrtStr ; Выводим адрес ошибочной строки
mov was_error,1 ; Устанавливаем флаг ошибки
ret ; Выход
cod4:mov al,ah ; Заносим в AL код команды
and al,01h ; Устанавливаем в 1 w-бит
and ah,00111000b; Установка битов в поле 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,0011100000000011b ; Установка битов в поле 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 ; Иначе ошибка: оба операнда - память
callWrtStr ; Выводим номер ошибочной строки
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:pushsi ; Запоминаем адрес начала операнда
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, а соответствий
callWrtStr ; не найдено, значит ошибка в операнде
mov was_error,1 ; Устанавливаем флаг ошибки
ret ; Выход
rm3:pop si ; Восст. адрес начала операнда
mov ah,[di] ; Заносим в AH код операции
xor al,al ; Обнуляем
or cod,ax ; Накладываем на код код операции
inc numbop ; Увеличиваем номер операнда
mov typeop,1 ; Устанавливаем тип операнда m
jmp cod11 ; Переход дальше
cod10:
Wrt error08 ; Выводим сообщение об ошибке
callWrtStr ; Выводим ошибочную строку
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 ; Увеличиваем адрес
loopcod13 ; Повторяем цикл
cod14: dec di ; Уменьшаем адрес
jmp cod2 ; Переход
Coding endp
aboutdb 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,'$'
mes1db 13,10,'$'
mes2db 13,10,'Трансляция завершена успешно$'
mes3db 13,10,'Обработано строк: $'
belldb 7,'$'
bufferdb1024 dup (32) ; Буфер для считывания данных
command db 'add' ; Транслируемая команда
path1dw 0 ; Адрес строки входного файла
path2dw 0 ; Адрес строки выходного файла
source dw 0 ; Обработчик входного файла
destdw 0 ; Обработчик выходного файла
; 00reg00w
Rtable db 'ax',1 ; 00000001b
db 'bx',25 ; 00011001b
db 'cx',9 ; 00001001b
db 'dx',17 ; 00010001b
db 'si',49 ; 00110001b
db 'di',57 ; 00111001b
db 'bp',41 ; 00101001b
db 'sp',33 ; 00100001b
db 'al',0 ; 00000000b
db 'ah',32 ; 00100000b
db 'bl',24 ; 00011000b
db 'bh',56 ; 00111000b
db 'cl',8 ; 00001000b
db 'ch',40 ; 00101000b
db 'dl',16 ; 00010000b
db 'dh',48 ; 00110000b
;mod000r/m
ExTabl db 5,'bx+si',0 ; 00000000b
db 5,'bx+di',1 ; 00000001b
db 5,'bp+si',2 ; 00000010b
db 5,'bp+di',3 ; 00000011b
db 2,'si',4 ; 00000100b
db 2,'di',5 ; 00000101b
db 2,'bx',7 ; 00000111b
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
outstrdb ' $'
Decimal endp
;┌──────────────────────────────┐
;│ Процедуравыводачисластрок │
;└──────────────────────────────┘
WrtStrproc near
xor ax,ax ; Обнулениерегистра AX
mov al,string ; В AL число обработанных строк
call Decimal ; Преобразуем в десятичный формат
Wrt outstr ; Выводим на экран
ret ; Выход
WrtStrendp
;┌─────────────────────────────┐
;│ Процедура удаления пробелов │
;└─────────────────────────────┘
DelSpcproc 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 ; Выход
DelSpcendp
;┌──────────────────────────┐
;│ Процедура открытия файла │
;└──────────────────────────┘
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
;┌──────────────────────────┐
;│ Процедуразакрытияфайла │
;└──────────────────────────┘
Fcloseproc near
mov ah,3eh ; Функция закрытия файла
int 21h ; Вызов прерывания DOS
jnc ok3 ; Переход, если файл успешно закрыт
Wrt error05 ; Вывод сообщения об ошибке
ok3: ret ; Выход
Fcloseendp
;┌────────────────────────┐
;│ Процедурачтенияфайла │
;└────────────────────────┘
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
;┌─────────────────────────┐
;│ Процедура записи в файл │
;└─────────────────────────┘
Fwriteproc 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 ; Выход
Fwriteendp
;┌──────────────────────────┐
;│ Процедураудаленияфайла │
;└──────────────────────────┘
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
;┌────────────────────────────────┐
;│ Процедуракодированияоперации │
;└────────────────────────────────┘
Codingproc 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,00111000b; Установка битов в поле 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,0011100000000011b ; Установка битов в поле 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 ; Переход
Codingendp
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,'$'
bufferdb 1024 dup (32) ; Буфер для считывания данных
command db 'cmp' ; Транслируемая команда
Addr1 dw 0 ; Адрес строки входного файла
Addr2 dw 0 ; Адрес строки выходного файла
sourcedw 0 ; Обработчик входного файла
dest dw 0 ; Обработчик выходного файла
; 00reg00w
RegTabl db 'ax',1 ; 00000001b
db 'bx',25 ; 00011001b
db 'cx',9 ; 00001001b
db 'dx',17 ; 00010001b
db 'si',49 ; 00110001b
db 'di',57 ; 00111001b
db 'bp',41 ; 00101001b
db 'sp',33 ; 00100001b
db 'al',0 ; 00000000b
db 'ah',32 ; 00100000b
db 'bl',24 ; 00011000b
db 'bh',56 ; 00111000b
db 'cl',8 ; 00001000b
db 'ch',40 ; 00101000b
db 'dl',16 ; 00010000b
db 'dh',48 ; 00110000b
; mod000r/m
MemTabl db 5,'bx+si',0 ; 00000000b
db 5,'bx+di',1 ; 00000001b
db 5,'bp+si',2 ; 00000010b
db 5,'bp+di',3 ; 00000011b
db 2,'si',4 ; 00000100b
db 2,'di',5 ; 00000101b
db 2,'bx',7 ; 00000111b
stringdb 0 ; Номер текущей строки
strlendw 0 ; Длина текущей строки
flag_eof db 0 ; Флаг конца файла (1-конец достигнут, 2-нет)
flag_err db 0 ; Флаг ошибки последней операции (1-была, 2-нет)
numbopdb 0 ; Номер операнда (0-первый, 1-второй)
typeopdb 0 ; Тип операнда (0-регистр, 1-память)
cmp_ dw 0 ; Записываемый код
addr2 dw 0 ; Адрес начала второго операнда
end begin
1. Анализ технического задания
В данном курсовом проекте необходимо разработать программу наязы-
ке Ассемблер для МП Intel 8086 реализующую функции транслятора всехмо-
дификаций команды ADD. Программа должна правильно распознавать тип адре-
сации (например регистр-регистр, регистр-память, память-регистр), иметь
подпрограммы обработки ошибок трансляции,выводить информацию о процес-
се трансляции и ошибках на экран дисплея.Команды для трансляции должны
быть оформлены в виде текстового файла,находящегося в одном каталоге с
программой-транслятором.При анализе команд трансляторомтакжедолжны
правильно обрабатываться:
- пустые строки
- строки с начальными и конечными пробелами
- строки-комментарии
- прописные и заглавные буквы
- ошибочные операторы
Результатом работы программы-транслятора должен быть выходной файл,
содержащий машинные коды оттранслированных команд. Входнойивыходной
файлы должны задаваться в командной строке запуска программы-транслято-
ра в виде параметров.
Для разработки транслятора понадобятся некоторые сведения острук-
туре команды ADD, обозначении регистров и способах адресации.
Объектный код команды ADD имеет следующий вид:
000000 d w mod reg r/m
───┬── ┬ ┬ ─┬─ ─┬─ ─┬─
│ │ ││ │ └──── Указательрегистр/память (3 бита)
│ │ ││ └──────── Типрегистра (3 бита)
│ │ │ └──────────── Тип адресации регистр/память (2 бита)
│ │ └─────────────── Размер регистра (0-байт, 1-слово)
│ └───────────────── Бит направления передачи
└───────────────────── Код операции
Регистры микропроцессора Intel 8086 кодируются следующим образом:
┌──────────────┬────────────┬───────────┐
│ Код регистра │ w=0 │ w=1 │
├──────────────┼────────────┼───────────┤
│ 000 │ AL │ AX │
│ 001 │ CL │ CX │
│ 010 │ DL │ DX │
│ 011 │ BL │ BX │
│ 100 │ AH │ SP │
│ 101 │ CH │ BP │
│ 110 │ DH │ SI │
│ 111 │ BH │ DI │
└──────────────┴────────────┴───────────┘
Биты MOD могут принимать следующие значения:
00 - биты r/m дают абсолютный адрес, байт смещения
(относительный адрес) отсутствует
01 - биты r/m дают абсолютный адрес памяти и имеется
один байт смещения
10 - биты r/m дают абсолютный адрес и имеется два
байта смещения
11 - биты r/m определяют регистр. Бит w (в байте кода
операции) определяет ссылку на восьми- или
шестнадцатибитовый регистр
Биты R/M определяют способ адресации следующим образом:
┌─────┬────────┐
│ R/M │ mod=00 │
├─────┼────────┤
│ 000 │ BX+SI│
│ 001 │ BX+DI│
│ 010 │ BP+SI│
│ 011 │ BP+DI│
│ 100 │SI │
│ 101 │DI │
│ 110 │ Direct │
│ 111 │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