Проектирование компилятора
Описание используемых директив и команд ассемблера и способов адресации. Выбор варианта построения ассемблера, проектирование алгоритмов и таблиц. Объектный код откомпилированного примера и его расшифровка. Графическая оболочка программы-компилятора.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 17.05.2013 |
Размер файла | 782,9 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru
Размещено на http://www.allbest.ru
Федеральное агентство по образованию
Государственно общеобразовательное учреждение
высшего профессионального образования
«Ижевский государственный технический университет»
Факультет «Информатика и вычислительная техника»
Кафедра «Вычислительная техника»
Пояснительная записка
к курсовому проекту по системному программному обеспечению
на тему «Проектирование компилятора»
Выполнил:
студент группы 6-78-3
Хохряков А.П.
Проверил:
к.т.н
Марков Е.М.
Ижевск, 2012
Содержание:
1. Введение 3
2. Расчет варианта задания 4
3. Разработка контрольного примера 4
4. Описание используемых директив и команд ассемблера и способов адресации 6
5. Выбор варианта построения ассемблера, описание алгоритмов и таблиц 7
6. Объектный код откомпилированного примера и его расшифровка 13
7. Заключение 15
Литература 35
Приложение: Исходные текст компилятора с подробными комментариями 16
Приложение: Графическая оболочка программы - компилятора: 34
1. Введение
компилятор программа команда таблица
В данной курсовой работе предусматривается разработка усеченной версии компилятора языка ассемблера для ЭВМ на базе микропроцессоров INTEL.
Разработка преследует следующие цели:
1) Закрепление теоретических знаний, полученных на лекциях дисциплины ”Системное программное обеспечение ЭВМ” по теме “Ассемблеры”;
2) Основная цель курсового проекта: Создание и исследование объектного файла. Объектный файл должен впоследствии восприниматься линковщиком и преобразовываться в исполняемый файл (COM или EXE). Данная цель включает подцели:
а) изучение дополнительного материала по архитектуре микропроцессоров INTEL, а именно изучение системы команд микропроцессора, форматов машинных команд и способов адресации;
б) изучение форматов объектных программ и загрузочных модулей.
2. Расчет варианта задания
3. Разработка контрольного примера
а) Алгоритм контрольного примера:
Жирным шрифтом выделены команды из базового набора.
Исходные данные - фиксированный массив целых чисел типа word (2 байта).
1) Вычесть из первого элемента следующий, из второго элемента - третий и так далее, суммируя все результаты вычитаний:
Используя оператор lahf можно загрузить флаговый регистр в регистр ah, редактируя и сохраняя значения этого регистра через sahf можно произвольно устанавливать флаги. Сами операторы lahf и sahf не влияют на флаги.
Таким образом можно осуществить работу цикла loopz (перейти пока сх<>0 и zf=1) используя редактирование флагового регистра.
2) Сдвиг результата вправо пока сдвигаемый бит не 0. Данная операция совершится минимум 1 раз для установки флага cf по которому с помощью опять же преобразований флагового регистра осуществляется работа цикла loopz - переход осуществляется не по флагу нуля (zf), а по флагу переноса.
3) Выйти из программы.
б) Код контрольного примера:
masm
model small
.stack 256
.486
.data
array dw 1313h
dw 0666h
.code
main:
;подключение кодового сегмента
mov ax,@data
mov ds,ax
;обрабатываемый массив целых чисел
lea si,array
mov ax,[si]
;сама программа
mov ax,8100h
dec ax
mov bx,FF00h
clc
rcr bx,08h
mov dx,ax
sub dx,bx
jo metka
metka:
;выход
mexit:
mov ax,4c00h
int 21h
end main
4. Описание используемых директив и команд ассемблера и способов адресации
Описание приведено для 16 разрядного ассемблера и работы только со словом (2 байта).
1) CLC - сброс флага переноса cf.
Алгоритм работы:
установка флага cf в ноль.
Состояние флагов после выполнения команды:
00 |
|
CF |
|
0 |
Применение:
Данная команда используется для сброса флага cf в ноль. Такая необходимость может возникнуть при работе с командами сдвига, арифметическими командами либо действиями по индикации обнаружения ошибок и различных ситуаций в программе.
2) JO - переход, если есть переполнение(OF = 1).
Команды условных переходов осуществляют переход по указанному адресу при выполнении условия, заданного мнемоникой команды. Если заданное условие не выполняется, переход не осуществляется, а выполняется команда, следующая за конкретной команой условного перехода. Переход осуществляется как вперед, так и назад в диапозоне +127...-128 байтов.
3) SUB - Целочисленное вычитание.
Алгоритм работы:
выполнить вычитание операнд1=операнд2-операнд1;
установить флаги.
Состояние флагов после выполнения команды:
11 |
07 |
06 |
04 |
02 |
00 |
|
OF |
SF |
ZF |
AF |
PF |
CF |
|
r |
r |
r |
r |
r |
r |
Применение:
Команда sub используется для выполнения вычитания целочисленных операндов или для вычитания младших частей значений многобайтных операндов.
4) RCR - Циклический сдвиг операнда вправо через флаг переноса.
Схема команды: |
rcr операнд,количество_сдвигов |
Назначение: операция циклического сдвига операнда вправо через флаг переноса cf.
Алгоритм работы:
сдвиг всех битов операнда вправо на один разряд; при этом младший бит операнда становится значением флага переноса cf;
одновременно старое значение флага переноса -- в операнд слева и становится значением старшего бита операнда;
указанные выше два действия повторяются количество раз, равное значению второго операнда команды rcr.
Состояние флагов после выполнения команды:
11 |
00 |
|
OF |
CF |
|
?r |
r |
Здесь обозначение ?r означает то, что анализ состояния флага имеет смысл при определенном сочетании операндов. В случае команды rcr флаг of представляет интерес, если сдвиг осуществляется на один разряд (см. ниже описание применения команды rcr).
Применение:
Команда rcr используется для циклического сдвига разрядов операнда вправо. Особенность этого сдвига в том, что он происходит с некоторой задержкой, так как очередной сдвигаемый бит оказывается на некоторое время вне операнда. В это время можно произвести его извлечение и (или) подмену. Другой важный момент заключается в том, что для счетчика сдвига микропроцессор использует только пять младших разрядов операнда количество_разрядов. Таким образом, значение, большее 31, не допускается (аппаратно это ограничение реализуется тем, что игнорируются значения битов счетчика старше пятого). Обратите внимание на еще один интересный эффект, связанный с поведением флага of, -- его значение имеет смысл только в операциях сдвига на один разряд и обусловлено тем, что по изменению этого флага можно судить о факте изменения знакового разряда операнда:
of=1, если текущие (то есть до операции сдвига) значения флага cf и старшего, левого бита операнда различны;
of=0, если текущие (то есть до операции сдвига) значения флага cf и старшего, левого бита операнда слева совпадают.
5) DEC - Уменьшение операнда на единицу.
Схема команды: |
dec операнд |
Назначение: уменьшение значения операнда в памяти или регистре на 1.Алгоритм работы: команда вычитает 1 из операнда. Состояние флагов после выполнения команды:
11 |
07 |
06 |
04 |
02 |
|
OF |
SF |
ZF |
AF |
PF |
|
r |
r |
r |
r |
r |
Применение:
Команда dec используется для уменьшения значения байта, слова, двойного слова в памяти или регистре на единицу. При этом заметьте то, что команда не воздействует на флаг cf.
Команды не из базового набора:
6) Mov -непосредственная и регистровая адресация
Назначение: пересылка данных между регистрами или регистрами и памятью.
направление пересылки в команде mov всегда справа налево, то есть из второго операнда в первый;
Применение:
значение второго операнда не изменяется;
оба операнда не могут быть из памяти;
лишь один из операндов может быть сегментным регистром;
Для проектируемого ассемблера используется операции обмена между регистрами, присвоение регистру значения непосредственного операнда и обращение к памяти через регистры - указатели на область оперативной памяти (si, di).
7) Lea
Назначение: получение эффективного адреса (смещения) источника.
Применение:
Данная команда является альтернативой оператору ассемблера offset. В отличие от offset команда lea допускает индексацию операнда, что позволяет более гибко организовать адресацию операндов.
Взаимодействует с таблицей переменных в проектируемом компиляторе, присваивает регистру (первый аргумент) смещение переменной (второй аргумент).
8) Int - непосредственный операнд
Назначение: вызов подпрограммы обслуживания прерывания с номером прерывания, заданным операндом команды.
Алгоритм работы:
записать в стек регистр флагов eflags/flags и адрес возврата. При записи адреса возврата вначале записывается содержимое сегментного регистра cs, затем содержимое указателя команд ip;
сбросить в ноль флаги if и tf;
передать управление на программу обработки прерывания с указанным номером.
5. Выбор варианта построения ассемблера, описание алгоритмов и таблиц
а) Особенности разрабатываемого ассемблера:
Программа располагается в одном сегменте и имеет один сегмент данных, то нет изменения адресов сегмента при использовании адресных операндов.
Адресные операнды -- задают физическое расположение операнда в памяти с помощью указания двух составляющих адреса: сегмента и смещения.
Основная задача ассемблера - разбор синтаксиса программы, выделение из строки программы директивы или команды и формирование машинных кодов.
Директивы ассемблера -- параметры (ключевые слова) в тексте программы на языке ассемблера, влияющие на процесс ассемблирования или свойства выходного файла.
Операторы ассемблера -- команды представляющие собой мнемокод машинных кодов операций, поддерживаемых каким - либо устройством.
б) Структура команды
В строке программы на ассемблере содержится одна команда, которая может быть как оператором, так и директивой.
Структура оператора:
Рис. 2. Структура оператора
Здесь обязательной частью служит мнемокод оператора, остальных частей может и не быть. Разделителями элементов являются пробелы и запятые. Если адресация регистровая то значение аргумента (имя регистра) влияет на машинный код операции (mov ax, bx и mov bx, ax), непосредственная адресация не влияет на машинный код операции, меняется непосредственный операнд в машинной записи оператора (mov ax,0123h).
Структура директивы:
Директива - имеет более разнообразную структуру, может состоять из множества частей.
Распознавание операторов и директив осуществляется с помощью их сравнения с описанными директивами и операторами.
Принцип формирования машинного кода:
Множество первых битов команд определяют тот или иной мнемокод операции (mov, add, jmp и другие). Этот код в зависимости от используемых регистров может модифицироваться (случай с pop push), т. е .к нему добавляется номер регистра.
Остальные биты команды могут также определять форматы аргументов. Для регистров ax, al формируются отличные от других регистров коды, некоторые операции процессоров оптимизированы при работе с регистром ах
Пример формирования кода команды:
shl ah,06h - код C0E406, где C0 - операция shl с 8 битными регистрами, E4 - адрес регистра приемника, 06 - константа, чисто 6 в 16 с/c
shl ch,06h - код C0E406, где C0 - операция shl с 8 битными регистрами, E5 - адрес регистра приемника(ch имеет номер на 1 больше аh), 06 - константа, чисто 6 в 16 с/c
mov cx,0003h - код B90300, здесь первый байт обозначает операцию перемещения константу 2 байта в 16-ти разрядный регистр. Код B9= B8 + № регистра приемника, т.е. 01. 0300 - байты константы с переставленными старшими и младшими байтами
в) Блок - схема алгоритма синтаксического разбора кода программы:
Пояснение к блок-схеме:
Этап формирование команды - синтаксическое форматирование, при котором остаются только элементы команды и разделители - пробелы, запятые и точка с запятой. в основном это избавление от двойных пробелов и пробелов около разделителей - запятых
Декомпозиция команды - разбиение команды на составные части:
-для оператора на метку, код операции и аргументы, конкретный элемент может
отсутствовать, кроме кода операции
-для директивы - на некоторые части
Декомпозиция применена для удобства дальнейшего распознания оператора или директивы путем сравнения с уже обозначенными в программе операторами и директивами.
г) Формирование сегмента команд и сегмента кода:
Результатом распознания оператора является машинный код, который хранится в специальном буфере для кодового сегмента.
Результатом распознания директивы является состав выходного *.obj файла (.data, .code), а также состав сегмента данных (name dw 1234h)
д) Особенности однопроходного компилятора:
Из двух вариантов построения ассемблера - однопроходной и многопроходной - был выбран однопроходной ассемблер.
1) Однопроходный компилятор компилирует программу, не возвращаясь назад, к уже откомпилированному тексту.
2) Однопроходный компилятор занимает больше памяти связи с формированием таблиц.
Из этих двух особенностей получается что объявлять переменные (имеющие относительные адреса - относительно сегмента данных) стоит до их использования, то же касается функций - но они не используются в разрабатываемом компиляторе.
Для переменных в памяти заводится специальная таблица переменных, с помощью которой компилятор производит подстановку вместо имени переменной - её смещения.
Что касается таблицы меток - обязательной части для операций безусловного и условного перехода - то во всех типах компиляторов присутствует их таблица.
е) Алгоритм осуществления безусловного и условных переходов:
При одном проходе компилятора формируется таблица меток (mark: - метка), на которые ссылаются соответственно операнды (jmp mark - операнд), работающие с метками, таблица имеет формат:
Пример 1):
Рис. 3. Таблица меток
Параллельно этой таблицы формируется таблица поправок (рис. 4.):
Разделение по таблицам работу с условными и безусловными переходами на таблицу метки (mark: - ссылка) и таблицу поправок т. е. запись операндов, использующий метку (jmp mark - операнд), нужно, чтобы учесть особенность, при которой метка может быть только одна, а переходов на неё с разных операторов может быть несколько.
На рис. 4 показана таблица поправок
Рис. 4. Таблица поправок
Рис. 3. и рис. 4 состояние таблиц после прохода компилятором всей программы.
После прохода всей программы из таблицы меток идет пересылка байтовых позиций меток (поле “Метка”) в таблицу поправок - это и есть поддержка того, чтобы была возможность ссылаться несколькими операторами на одну метку. Принадлежность метки оператору определяется через имя метки - для этого и введено поле “Имя” (“Имя метки”) в обе таблицы.
Следующий пример показывает, как несколько операторов вызывают одну и ту же метку, и происходит столько добавлений ссылок метки, сколько таких операторов:
Пример 2):
1) Программа: 2) Таблица меток: 3) Таблица поправок (2 оператора):
Рис. 5. Работа с метками, когда несколько переходов на одну метку
Пример показывает необходимость хранить метки и переходы операторов по этим меткам в разных таблицах. До окончания прохода программы неизвестно, сколько будет переходов, добавление ссылок в таблицу меток идет после прохода всей программы.
Операторы перехода в разрабатываемом компиляторе имеют все короткий переход (-128..127 байт). Этот переход есть смещение в байтах текущего указателя команды ip. Оно вычисляется с помощью таблицы меток как разность полей:
“Метка” - “Вызов метки” + учет длины оператора вызова (2 байта)
для конкретной метки и далее добавляется с использованием поля “Строка” в соответствующую строку программы, после того как вся программа просмотрена.
ж) Алгоритм Работы с переменными:
Приняв формат всех переменных только за слово типа word (2 байта) и один сегмент для всех данных получается очень постой алгоритм для работы с переменными:
Рис. 6. Таблица переменных
Адрес переменной - адрес относительно начала сегмента данных, адрес для конкретной переменной равен её позиции в таблице, начиная с 0, умноженную на 2 (word 2 байта - конкретно для этой таблицы). Компилятор встречая имя переменной в качестве операнда - заменяет его на адрес метки в соответствии с таблицей.
Примечание: для подключения сегмента данных используется специальный вспомогательный сегмент - константа: “9c0500c801550140”, стоящий в *.obj файле перед сегментом данных.
з) Выявление ошибок:
1) Для распознавания оператора или директивы используется сравнение с уже существующими в программе операторами и директивами, если сравнение не прошло, то оператор или директива нераспознаны и формируется ошибка:
<Неизвестная команда>
2) Каждая метка должна быть указана только один раз, иначе возникает неопределенность перехода по ней. Для предотвращения переопределения происходит простое сравнение новый метки с существующими с помощью таблицы меток. В этом случае генерируется ошибка:
<Переопределение метки>
3) Ошибка неизвестной переменной формируется, если переменная не объявлена или объявлена после использования:
<Необъявленная переменная>
4) Указание мнемокода команды без описания обязательных аргументов генерирует ошибку:
<Неизвестный аргумент>
Рис. 7. Примеры ошибок
6. Объектный код откомпилированного примера и его расшифровка
Рис. 8. Объектный код в программе - редакторе шестнадцатеричного кода
Разбор объектного кода:
00 - обозначение контрольного байта
00 - обозначение длины записи в объектном файле в байтах
00 - обозначение слов (слов или двойных слов) в сегменте данных
- длина сегмента данных (если поменять местами байты - старший с младшим)
Исходя из того что разрабатываемый компилятор будет воспринимать весь код в одном сегменте кода, а все данные в одном сегменте данных, то можно выделить некую общую часть объектного файла для всех программ созданных на этом компиляторе как постоянную (заголовок).
Часть 1) Заголовок .obj файла:
80 0D 00 0b 70 72 6F 67 72 61 6D 2E 61 73 6D 01 - имя компилируемого файла “program.asm”
88 0E 00 00 00 1c 43 6F 4D 70 49 4C 61 54 6F 52 D4 - версия ассемблера “CoMpILaToR”
88 13 00 40 e9 5c 06 89 3c 0b 70 72 6f 67 72 61 6d 2e 61 73 6d a3 - копия имени компилируемого файла “program.asm”
88 03 00 40 e9 4c
96 02 00 00 68
88 03 00 40 a1 94
- постоянные записи неизвестного назначения
96 0c 00 05 5f 54 45 58 54 04 43 4f 44 45 96 - описание служебного сегмента кода “_TEXT” “CODE”
98 07 00 48 24 00 02 03 01 05 - описание данных сегмента кода (его тип всегда 48 - word public)
96 0c 00 05 5f 44 41 54 41 04 44 41 54 41 c2 - описание служебного сегмента данных “_DATA” “DATA”
98 07 00 48 00 00 04 05 01 0f - описание данных сегмента (его тип всегда 48 - word public)
96 0d 00 05 53 54 41 43 4b 05 53 54 41 43 4b 67 - стековый сегмент “STACK”
98 07 00 74 00 01 06 07 01 de - запись, относящаяся к стеку, 0100 (это есть 0001) - длина стека = 256 байт
96 08 00 06 44 47 52 4f 55 50 8b - описание группы сегментов “DGROUP”
9a 06 00 08 ff 03 ff 02 55 - описание группы сегментов “DGROUP”
88 04 00 40 a2 01 91 - запись начала сегментов
Часть 2) Сегмент кода:
a0 24 00 01 00 00 b8 00 00 8e d8 be 00 00 8b 04 B8 00 81 48 BB 00 ff f8 c1 DB 08 8b D0 2b D3 70 B8 00 4c cd 21 3E
Код первой команды b8 00 00 (mov ax,@data). Байты 2400 говорят о длине сегмента в байтах, это же длина должна быть указана в описании данных сегмента кода (98 07 00 48 24 00 02 03 01 05) Соответствие команд машинным кодам показана в компиляторе (Рис. 1а. в приложении ).
Часть 3) Сегмент данных:
Перед сегментом данных хранится вспомогательный сегмент
9c 05 00 c8 01 55 01 40 - необходим чтобы при выполнение команд:
mov ax,@data
mov ds,ax
правильно установился адрес сегмента данных в регистр данных. Адрес сегмента данных зависит от той области памяти куда загружен сегмент - это устанавливается ОС, а уже смещение внутри сегмента - контролируется компилятором в зависимости от таблицы имен переменных.
Сегмент данных:
a0 08 00 02 00 00 13 13 66 06 C4 - слова хранятся в порядке объявления
Часть 4) Окончание программы
8a 07 00 c1 00 01 01 00 00 ac - окончание программы, начало программы задано явно (0000).
7. Заключение
Ассемблер - аппаратно зависимый язык программирования. Компилятор строится для архитектуры процессора Intel (80X86) что требует дополнительно изучения архитектуры данного процессора, а не только умений ассемблирования.
Сложность построения компилятора резко возрастает, если необходимо поддерживать возможность использования множества сегментов, описывать внешние метки.
Разрабатываемый компилятор обладает одним сегментом данных и одним сегмент кода, это упрощает процесс транслирования.
Существенная роль отводится синтаксическому разбору команд программы. В зависимости от типа аргументов появляется тот или иной способ адресации связанный с архитектурой процессора. Одна и та же операция имеет множество разнообразий форматов аргументов и следовательно множество машинных кодов.
Что касается объектного файла - то ограниченность возможностей компилятора позволяет работать только с парой сегментов в объектной файле, при этом остальная часть объектного файла постоянна и не изменяется при модификации программы.
Литература
1). Проектирование компилятора. Методические указания по курсовой работе по дисциплине “Системное программное обеспечение для студентов специальности 220100”, ИжГТУ 2003, 24 стр.
2). http://www.kolasc.net.ru/cdo/programmes/assembler/tc.html - справка команд ассемблера
3). http://james.hernon.tripod.com - Intel 8086 Family Architecture. Мнемокоды команд.
4). http://www.mlsite.net/8086/ - Мнемокоды команд.
Приложение: Исходные текст компилятора с подробными комментариями
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, ExtCtrls, ComCtrls, Menus;
type
//Тип данных из нестандартных:
Directive = record
part1:string;
part2:string;
part3:string;
MashCode:string;
exist:boolean; //признак того, что директива описана и распознаётся
end;
Command = record
mark:string;
oper:string;
arg1:string;
arg2:string;
MashCode:string;
ByteLen:string;
exist:boolean; //признак того что оператор описан и распознаётся
end;
Prog = record
isCodeSeg:boolean; //наличие сегмента кода
isDataSeg:boolean; //наличие сегмента данных
end;
TForm1 = class(TForm)
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
Label4: TLabel;
Code: TMemo;
modifadress: TButton;
marks: TStringGrid;
Title: TMemo;
SaveButton: TButton;
CodeSeg: TMemo;
DataSeg: TMemo;
EndFile: TMemo;
MainMenu1: TMainMenu;
Program1: TMenuItem;
Exit1: TMenuItem;
exeOne: TButton;
exeAll: TButton;
CreateObjFile: TButton;
MashData: TMemo;
Label2: TLabel;
Varibles: TStringGrid;
ScrollBar1: TScrollBar;
DataSourceSeg: TMemo;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
Label10: TLabel;
Label11: TLabel;
markslinks: TStringGrid;
Label12: TLabel;
Label13: TLabel;
Label14: TLabel;
GroupBox1: TGroupBox;
ComBytePosMemo: TMemo;
MashCode: TMemo;
Label1: TLabel;
Label3: TLabel;
SaveMenu: TMenuItem;
ClearCodeButton: TButton;
Edit1: TEdit;
TranslAndSaveMenu: TMenuItem;
CmplName: TEdit;
FileName: TEdit;
Label15: TLabel;
Label16: TLabel;
NewProgramButton: TButton;
procedure CodeChange(Sender: TObject);
procedure NewProgramButtonClick(Sender: TObject);
procedure TitleDblClick(Sender: TObject);
procedure TranslAndSaveMenuClick(Sender: TObject);
procedure Edit1Click(Sender: TObject);
procedure ClearCodeButtonClick(Sender: TObject);
procedure ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
procedure CreateObjFileClick(Sender: TObject);
procedure exeAllClick(Sender: TObject);
procedure exeOneClick(Sender: TObject);
procedure Exit1Click(Sender: TObject);
procedure SaveButtonClick(Sender: TObject);
procedure modifadressClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
//расчет мнемокода
function insRegMul(mem:string; arg:string; koef:integer):string;
function insReg(mem:string; arg:string):string;
function cnvROM(imm:string):string;
function cnvData(dat:string):string;
function cnv(imm:string):string;
function isImm(arg:string):boolean;
function isData(str:string):boolean;
function isReg(arg:string):boolean;
function isSmallReg(arg:string):boolean;
function NexStrToStr(nexstr:string):string;
function IntToHexStr(int:integer):string;
function AnalysisCommand (comstr:string):command;
function ComNext:string;
function ComRead:string;
function ComIs:string;
function DeleteSpace(str:string):string;
function DecompositeCommand(comstr:string):Command;
function ModifyMarkAdress:string;
function AddLinksInMarkers:boolean;
function MarkTableWrite(Mname,LBytepos,CBytepos,Strpos:string):boolean;
function MarksLinksTableWrite(Mname,LBytepos:string):boolean;
function ViewOnlyHex(txt:string):string;
function AddControlByte(strhex:string):string;
function ComExe:boolean;
function AnalysisDirective(DrcStr:string):directive;
function DecompositeDirective(DrcStr:string):directive;
function DataTableWrite(Varible:string; Len:string):boolean;
function IntToIIII(Int:integer):string;
function GetVarCodeByName(name:string):string;
//управление прокруткой
function SlideDown:boolean;
function SlideUp:boolean;
function StrToHexStr(str:string):string; //перевод из Ansi в hex
private
{ Private declarations }
public
{ Public declarations }
end;
//Глобальные переменные
var
Form1: TForm1;
ThisProgram:Prog; //параметр программы (контроль за наличием сегментов)
Reg16,Reg8:array of string; //динамический список имен регистров (нумерация для мнемокодов)
ComReadPos:integer;
ComBytePos:integer;
DataBytes:integer; //для формирования сегмента данных
ErrorControl:string; //для хранения ошибки
RegLen:string; //хранение размера регистра при анализировании команды
implementation
{$R *.dfm}
//добавить к мнемокоду номер рагистра*k, указанного в аргументе: ('A0' + 'cx' = 'A1')
function TForm1.insRegMul(mem:string; arg:string; koef:integer):string;
var pos:integer; intcode:integer;
begin
intcode:=ord(NexStrToStr(mem)[1]); //16-ый код - строка (пример: 'A0') переводится в целое число
//получение номера регистра:
if (RegLen='R16') then for pos:=0 to length(Reg16) do if arg=Reg16[pos] then break;
if (RegLen='R8') then for pos:=0 to length(Reg8) do if arg=Reg8[pos] then break;
intcode:=intcode+pos*koef; //добавление позиции регистра к мнемокоду
mem:=IntToHex(intcode,2); //перевод обратно в 16-ый код - строку
insRegMul:=mem;
end;
//добавить к мнемокоду номер рагистра, указанного в аргументе: ('A0' + 'cx' = 'A1')
function TForm1.insReg(mem:string; arg:string):string;
var pos:integer; intcode:integer;
begin
pos:=0;
intcode:=ord(NexStrToStr(mem)[1]); //16-ый код - строка (пример: 'A0') переводится в целое число
//получение номера регистра:
if (RegLen='R16') then for pos:=0 to length(Reg16) do if arg=Reg16[pos] then break;
if (RegLen='R8') then for pos:=0 to length(Reg8) do if arg=Reg8[pos] then break;
edit1.Text:=edit1.Text+'$pos='+inttostr(pos);
intcode:=intcode+pos; //добавление позиции регистра к мнемокоду
mem:=IntToHex(intcode,2); //перевод обратно в 16-ый код - строку
insReg:=mem;
end;
function TForm1.StrToHexStr(str:string):string; //перевод текста в строку в код 16 с/c
var pos:integer; hexstr:string;
begin
hexstr:='';
for pos:=1 to length(str) do hexstr:=hexstr+IntToHexStr(ord(str[pos]));
StrToHexStr:=hexstr;
end;
function TForm1.SlideDown:boolean;
begin
Code.Perform(WM_VSCROLL, SB_LINEDOWN, 1);
MashData.Perform(WM_VSCROLL, SB_LINEDOWN, 1);
MashCode.Perform(WM_VSCROLL, SB_LINEDOWN, 1);
ComBytePosMemo.Perform(WM_VSCROLL, SB_LINEDOWN, 1);
end;
function TForm1.SlideUp:boolean;
begin
Code.Perform(WM_VSCROLL, SB_LINEUP, 1);
MashData.Perform(WM_VSCROLL, SB_LINEUP, 1);
MashCode.Perform(WM_VSCROLL, SB_LINEUP, 1);
ComBytePosMemo.Perform(WM_VSCROLL, SB_LINEUP, 1);
end;
procedure TForm1.TitleDblClick(Sender: TObject);
begin
Title.Text:=StrToHexStr(FileName.Text);
end;
procedure TForm1.TranslAndSaveMenuClick(Sender: TObject);
begin
ExeAll.Click; //транслирование всей программы
ModifAdress.Click; //установка смещений для операторов условного безусловного перехода
CreateObjFile.Click; //Формирование объектного файла
SaveButton.Click; //сохранение
end;
function TForm1.GetVarCodeByName(name:string):string; //из таблицы переменных взять код переменной по имени
var row:integer; adrs:string;
begin
adrs:='';
for row:=1 to Varibles.RowCount-1 do if Varibles.Cells[0,row]=name then adrs:=Varibles.Cells[1,row];
if adrs<>'' then GetVarCodeByName:=adrs
else ErrorControl:='<Необъяв. перемен.>';
end;
function TForm1.IntToIIII(Int:integer):string;//преообазование целого числа в 16 с/c в 4 позиции (2байта)
var res:string;
begin
res:=IntToHex(Int,4);
IntToIIII:=res;
end;
function TForm1.DataTableWrite(Varible:string; Len:string):boolean; //запись в таблицу переменных
var row:integer;
begin
//ComBytePos глобальная переменная - счетчик байтов для записи переменных в сегмент данных
Varibles.RowCount:=Varibles.RowCount+1;
Varibles.FixedRows:=1;
row:=Varibles.RowCount-1;
Varibles.Cells[0,row]:=Varible;
Varibles.Cells[1,row]:=IntToIIII(DataBytes);
if Len='dd' then DataBytes:=DataBytes+4;
if Len='dw' then DataBytes:=DataBytes+2;
end;
function TForm1.DecompositeDirective(DrcStr:string):directive;
var pos:integer;
begin
//начальные значения
DecompositeDirective.part1:='';
DecompositeDirective.part2:='';
DecompositeDirective.part3:='';
//установка ограничения для строки-директивы
DrcStr:=DrcStr+' ';
//1)извлечение первой части:
for pos:=1 to length(DrcStr) do if DrcStr[pos]=' ' then begin
DecompositeDirective.part1:=copy(DrcStr,1,pos-1);
Delete(DrcStr,1,pos);
Break;
end;
//2)извлечение второй части:
for pos:=1 to length(DrcStr) do if DrcStr[pos]=' ' then begin
DecompositeDirective.part2:=copy(DrcStr,1,pos-1);
Delete(DrcStr,1,pos);
Break;
end;
//3)извлечение третьей части:
for pos:=1 to length(DrcStr) do if DrcStr[pos]=' ' then begin
DecompositeDirective.part3:=copy(DrcStr,1,pos-1);
Delete(DrcStr,1,pos);
Break;
end;
end;
function TForm1.AnalysisDirective(DrcStr:string):directive;
var drc:directive;
begin
drc:=DecompositeDirective(DrcStr);
with drc do BEGIN
exist:=false;
//dd,dw
if (part1<>'') and ((part2='dd')or(part2='dw')) and isImm(part3) then begin
MashCode:=CnvRom(part3);
DataTableWrite(part1,part2);
exist:=true;
end;
//dd,dw без имени переменной
if ((part1='dd')or(part1='dw')) and isImm(part2) then begin
MashCode:=CnvRom(part2);
DataTableWrite('',part1);
exist:=true;
end;
if (part1='masm') then exist:=true;
if (part1='.code') then exist:=true;
if (part1='.data') then exist:=true;
if (part1='model') and (part2='small') then exist:=true;
if (part1='.stack') then exist:=true;
if (part1='.486') then exist:=true;
if (part1='end') then exist:=true;
END;
AnalysisDirective:=drc;
end;
procedure TForm1.CodeChange(Sender: TObject);
begin
end;
function TForm1.ComExe:boolean; //транслирование строки программы
var com:command; //команда записанная в специальной записи - команда
drc:directive; //дирректива записанная в специальной записи - дирректива
comstr:string; //команда в текстовом виде
pos:integer;
begin
//добавление строк в байтовый счетчик, кодовую часть и часть данных
MashCode.Lines.Add('');
MashData.Lines.Add('');
ComBytePosMemo.Lines.Add('');
//проверка на строку-пустоту или строку-сплошной комментарий:
//..если встречается такая строка, то выход без обработки
comstr:=ComRead;
//если строка в коде программы является полностью комментарием:
if length(comstr)>=1 then begin
pos:=1; while (comstr[pos]=' ')and(pos<length(comstr)) do inc(pos);
if comstr[pos]=';' then exit;
end;
//если строка является пустой:
if comstr='' then exit;
//обработка команд - операторов
com:=AnalysisCommand(comstr);
MashCode.Lines[ComReadPos]:=com.MashCode;
if com.ByteLen<>'' then ComBytePos:=ComBytePos + strtoint(com.ByteLen);
ComBytePosMemo.Lines[ComReadPos]:=inttostr(ComBytePos);
//обработка команд - директив
drc:=AnalysisDirective(ComRead);
MashData.Lines[ComReadPos]:=drc.MashCode;
//----------------------------------------------------------------------------->
//выявление ошибок в синтаксисе:
if com.MashCode<>'' then com.exist:=true; //если есть машинный код то оператор распознан
if (not com.exist) and (not drc.exist) //если ни директива, ни оператор не распознаны то:
then MashCode.Lines[ComReadPos]:='<Неизв. ком.>';
//анализ сообщений об ошибках:
if ErrorControl<>'' then MashCode.Lines[ComReadPos]:=ErrorControl;
ErrorControl:=''; //стирание сообщений об ошибках
//----------------------------------------------------------------------------->
end;
function TForm1.AddControlByte(strhex:string):string; //вычисление контрольного байта
var sum,pos:integer;
begin
sum:=0;
pos:=1; while (pos<=length(strhex)) do begin
sum:=sum+strtoint('$'+copy(strhex,pos,2));
pos:=pos+2;
end;
sum:=256 - sum mod 256;
AddControlByte:=strhex+IntToHexStr(sum);
end;
//удаление пробелов и переносов
function TForm1.ViewOnlyHex(txt:string):string;
var pos:integer;
begin
pos:=1; while (pos<=length(txt)) do begin
if txt[pos]=' ' then begin delete(txt,pos,1); dec(pos) end;
if txt[pos]=chr(13) then begin delete(txt,pos,1); dec(pos) end;
if txt[pos]=chr(10) then begin delete(txt,pos,1); dec(pos) end;
inc(pos);
end;
ViewOnlyHex:=txt;
end;
function TForm1.MarksLinksTableWrite(Mname,LBytepos:string):boolean;
var row:integer;
begin
//поиск введеной метки среди существующих
row:=1; while (row<=markslinks.RowCount-1) do begin
if markslinks.Cells[0,row]=Mname then begin
//если поиск успешен - то вывод ошибки (повторное описание ссылки метки)
ErrorControl:='<Переопр. метки>';
exit;
end;
inc(row);
end;
//если вносимой ссылки нет - то внести её
markslinks.RowCount:=row+1; //row указывает на конец таблицы
if Mname <>'' then markslinks.Cells[0,row]:=Mname;
if LBytepos<>'' then markslinks.Cells[1,row]:=LBytepos;
markslinks.FixedRows:=1; //выделить заголовок таблицы
end;
function TForm1.MarkTableWrite(Mname,LBytepos,CBytepos,Strpos:string):boolean;
var row:integer;
begin
//добавление ссылки метки:
if LBytepos<>'' then begin
//добавление ко всем меткам ссылок
row:=1; while (row<=marks.RowCount-1) do begin
if marks.Cells[0,row]=Mname then if LBytepos<>'' then marks.Cells[1,row]:=LBytepos;
inc(row);
end;
end;
//добавление оператора, использующего метку
if CBytepos<>'' then begin
marks.RowCount:=marks.RowCount+1;
marks.FixedRows:=1;
row:=marks.RowCount-1;
if Mname <>'' then marks.Cells[0,row]:=Mname;
if CBytepos<>'' then marks.Cells[2,row]:=CBytepos;
if Strpos <>'' then marks.Cells[3,row]:=Strpos;
exit;
end;
end;
function TForm1.ModifyMarkAdress:string; //рассчет смещений и добавление их в сегмент кода
var row:integer;
begin
for row:=1 to marks.RowCount-1 do
if (marks.Cells[0,row]<>'')and(marks.Cells[2,row]<>'') then begin
MashCode.Lines[strtoint(marks.Cells[3,row])]:=
MashCode.Lines[strtoint(marks.Cells[3,row])]+
IntToHexStr( strtoint(marks.Cells[1,row])-strtoint(marks.Cells[2,row]) );
end;
end;
function TForm1.AddLinksInMarkers:boolean; //добавление ссылок в таблицу меток
var row:integer;
begin
row:=1; while row<=markslinks.RowCount-1 do begin
MarkTableWrite( markslinks.Cells[0,row],markslinks.Cells[1,row],'','' );
inc(row);
end;
end;
function TForm1.IntToHexStr(int:integer):string; //преобразование целого числа в строку - 16-ую запись этого числа
var res:string;
begin
res:=IntToHex(int,2);
while length(res)>2 do delete(res,1,1);
IntToHexStr:=res;
end;
function TForm1.DecompositeCommand(comstr:string):Command;
var posi:integer; oper,mark,arg1,arg2:string;
begin
//обнуление параметров:
mark:='';
oper:='';
arg1:='';
arg2:='';
//для форматов "mark:mov ax,bx; comments" =метка + команда с двумя операндами + коментарий
// "mov ax,bx" =команда с двумя операндами
// "inc ax" =команда с одним операндом
// "aam" =команда без операндов
//если строка является полностью коментарием
if length(comstr)>=1 then begin
posi:=1; while (comstr[posi]=' ')and(posi<length(comstr)) do inc(posi);
if comstr[posi]=';' then comstr:='';
end;
//установка ограничения для строки-команды
comstr:=comstr+' ';
//замена разделителя коментария ( символ ';' ) на пробел
posi:=pos(';',comstr); if posi>0 then comstr[posi]:=' ';
//1)извлечение метки
for posi:=1 to length(comstr) do if comstr[posi]=':' then begin
mark:=copy(comstr,1,posi-1);
Delete(comstr,1,posi);
Break;
end;
//2)извлечение мнемокода операции
for posi:=1 to length(comstr) do if comstr[posi]=' ' then begin
oper:=copy(comstr,1,posi-1);
Delete(comstr,1,posi);
Break;
end;
//3)извлечение первого операнда
for posi:=1 to length(comstr) do if comstr[posi]=',' then begin
arg1:=copy(comstr,1,posi-1);
Delete(comstr,1,posi);
Break;
end;
//4)извлечение второго операнда
for posi:=1 to length(comstr) do if (comstr[posi]=' ') then begin
arg2:=copy(comstr,1,posi-1);
Delete(comstr,1,posi);
Break;
end;
//Для данного алгоритма: если второй операнд есть, а первого нет то это значит что команда одноаргументная:
//..нужно выполнить пересылку аргумета из 2 в 1:
if (arg1='')and(arg2<>'') then begin
arg1:=arg2;
arg2:='';
end;
//Запись результатов в параметр возвращаемый процедурой:
DecompositeCommand.mark:=mark;
DecompositeCommand.oper:=oper;
DecompositeCommand.arg1:=arg1;
DecompositeCommand.arg2:=arg2;
end;
//Удаление пробелов перед и после команды, а также двойных пробелов и пробелов
//..перед символами разделения (запятая и т. д.)
function TForm1.DeleteSpace(str:string):string;
var ps:integer;
begin
if str=' ' then str:='';
if str='' then exit;
//удаление пробелов до и после команды:
while ((str[1]=' ')and(length(str)>1)) do delete(str,1,1);
while ((str[length(str)]=' ')and(length(str)>1)) do delete(str,length(str),1);
//удаление двойных пробелов:
ps:=1; while ps <= length(str)-1 do begin
if ((str[ps]=' ') and (str[ps+1]=' ')) then begin delete(str,ps,1); ps:=0; end;
inc(ps);
end;
//удаление пробелов рядом с разделителем - запятой
ps:=Pos(',',str);
if ps>0 then begin
if str[ps+1]=' ' then delete(str,ps+1,1);
if str[ps-1]=' ' then delete(str,ps-1,1);
end;
DeleteSpace:=str;
end;
procedure TForm1.Edit1Click(Sender: TObject); //Событие для тестирования - можно удалить
var pos:integer;
begin
//Edit1.Text:=insReg('10','si');
//if isReg('no') then Edit1.Text:='reg' else Edit1.Text:='no reg';
//if isImm('data') then Edit1.Text:='imm' else Edit1.Text:='no imm';
//if isSmallReg('al') then Edit1.Text:='small' else Edit1.Text:='no small';
//isReg('si');
//Edit1.Text:=RegLen;
Edit1.Text:=cnvROM('0A1010101h');
end;
function TForm1.ComIs:string; //Есть ли команда или уже уже конец файла
begin
if (ComReadPos<Code.Lines.Count) then ComIs:=''
else ComIs:='EOF';
end;
function TForm1.ComNext:string; //Переход на следующую команду или сброс:
begin
inc(ComReadPos);
end;
//Считывание очередной считанной команды и возврат её функцией в текстовом виде
function TForm1.ComRead:string;
begin
//LowerCase - все буквы (от A до Z) устанавл прописными
ComRead:=LowerCase(DeleteSpace(Code.Lines[ComReadPos])); //DeleteSpace - удалние пробелов
end;
//Получение Imm16 с перестановкой байтов в Imm16 и убирание символа 'h'
function TForm1.cnvROM(imm:string):string;
begin
//если слово
if (length(imm)>=5)and(length(imm)<9) then while length(imm)<>5 do delete(imm,1,1);
//убирание лишних символов слева:
if length(imm)<=5 then begin cnvROM:=copy(imm,3,2)+copy(imm,1,2); exit; end;
//если двойное слово
//убирание лишних символов слева:
if length(imm)>9 then while length(imm)<>9 do delete(imm,1,1);
if length(imm)=9 then cnvROM:=copy(imm,7,2)+copy(imm,5,2)+copy(imm,3,2)+copy(imm,1,2);
end;
//Получение кода в 16 c/c, являющегося смещением относительно положения si (для операндов вида [si+N])
function TForm1.cnvData(dat:string):string;
begin
if pos('+',dat)>0 then //если указано смещение т.е. si+N, где N - велич смещения
cnvData:=copy(dat,pos('+',dat)+1,2) //получение 2-х символов после символа +, пдразумевается что эти символы число в 16 с/c
else cnvData:='*'; //смещение не указано
end;
//Получение кода в 16 с/с аргумента байта
function TForm1.cnv(imm:string):string;
begin
cnv:=copy(imm,1,2);
end;
// Проверка на непосредственный операнд (пример mov ax,0140h - 0140h = Imm16):
function TForm1.isImm(arg:string):boolean;
var pos:integer; hexset: set of char;
begin
isImm:=true;
hexset:=['0'..'9','a'..'f'];
if arg[length(arg)]<>'h' then isImm:=false;
for pos:=1 to length(arg)-1 do if not (arg[pos] in hexset) then isImm:=false;
//не является ли непосредственный операнд регистром:
for pos:=0 to length(Reg16)-1 do if (Reg16[pos]<>'') then if (arg=Reg16[pos]) then begin isImm:=false; break; end;
for pos:=0 to length(Reg8)-1 do if (Reg8[pos]<>'') then if (arg=Reg8[pos]) then begin isImm:=false; break; end;
end;
// Проверка на непосредственный операнд (пример mov ax,0140h - 0140h = Imm16):
function TForm1.isReg(arg:string):boolean;
var pos:integer;
begin
isReg:=false; //убрать признак, что аргумент регистр
RegLen:=''; //убрать информацию о длине регистра
//является ли операнд - регистром:
for pos:=0 to length(Reg16)-1 do if (Reg16[pos]<>'') then
if (arg=Reg16[pos]) then begin isReg:=true; RegLen:='R16'; break; end;
for pos:=0 to length(Reg8)-1 do if (Reg8[pos]<>'') then
if (arg=Reg8[pos]) then begin isReg:=true; RegLen:='R8'; break; end;
end;
//проверка аргумента на 8 битный регистр
function TForm1.isSmallReg(arg:string):boolean;
var pos:integer;
begin
isSmallReg:=false;
for pos:=0 to length(Reg8)-1 do
if (Reg8[pos]<>'') then if (arg=Reg8[pos]) then begin isSmallReg:=true; break; end;
end;
// Проверка на взаимодействие с областью сегмента данных через si (mov ax,[si+4]):
function TForm1.isData(str:string):boolean;
var i:integer;
begin
isData:=false;
if Pos('[',str)>0 then if Pos(']',str)>0 then if Pos('si',str)>0 then isData:=true;
end;
// Функция преобразования строки с шестнадцатеричными символами эквивалентой 1 байту в символ:
function TForm1.NexStrToStr(nexstr:string):string;
begin
if length(nexstr)=2 then NexStrToStr:=chr(strtoint('$'+nexstr));
if length(nexstr)=4 then NexStrToStr:=chr(strtoint('$'+copy(nexstr,1,2)))+
chr(strtoint('$'+copy(nexstr,3,2)));
if length(nexstr)=6 then NexStrToStr:=chr(strtoint('$'+copy(nexstr,1,2)))+
chr(strtoint('$'+copy(nexstr,3,2)))+
chr(strtoint('$'+copy(nexstr,5,2)));
end;
procedure TForm1.NewProgramButtonClick(Sender: TObject);
begin
//установка указателя для считывания на начало программы
ComReadPos:=0;
//установка счетчика положения команд в байтах на начало
ComBytePos:=0;
//обнуление счетчика для записи переменных в сегмент даных
DataBytes:=0;
//обнуление
marks.RowCount:=1; //таблицы поправок
varibles.RowCount:=1; //таблицы переменных
markslinks.RowCount:=1; //таблицы меток
//обнуление буферов - содержимых сегментов
ComBytePosMemo.Text:='';
MashCode.Text:='';
MashData.Text:='';
Title.Text:='';
CodeSeg.Text:='';
DataSeg.Text:='';
end;
procedure TForm1.ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode;
var ScrollPos: Integer);
begin
if (ScrollCode=scLineDown) then SlideDown;
if (ScrollCode=scLineUp) then SlideUp;
end;
//Возврат машинного кода после распознавания мнемокода, установка длины команды, проверка существования команды
function TForm1.AnalysisCommand (comstr:string):command;
var com:command;
begin
com:=DecompositeCommand(comstr);
//обнуление выходных параметров - если программа не опознана то выводится
//..предупреждение о неизв. команде
com.MashCode:='';
com.ByteLen:='';
com.exist:=false; //первоначально команда считается не распознаной
with com do BEGIN
if (oper='mov') then begin//------------------------------------------------MOV
//предпроверка
//проверка правильности использования команды:
if isReg(arg1) then if RegLen='R16' then if isReg(arg2) then if RegLen='R8' then begin ErrorControl:='<Неcоотв. типов арг.>'; exit; end;
if isReg(arg1) then if RegLen='R8' then if isReg(arg2) then if RegLen='R16' then begin ErrorControl:='<Неcоотв. типов арг.>'; exit; end;
//проверка указания всех аргументов
if (arg1='')or(arg2='') then begin ErrorControl:='<Неуказ. все аргум.>'; exit; end;
if (arg1='ds') then if (arg2='ax') then begin //mov ds-ax
MashCode:='8ed8';
ByteLen:='2'; end;
if (oper='mov') then if isReg(arg1) then if isReg(arg2) then begin
if (RegLen='R16') then begin MashCode:='8b'+InsReg( InsRegMul('c0',arg1,8) , arg2 ); ByteLen:='2'; end;//mov R16-R16
if (RegLen='R8') then begin MashCode:='8a'+InsReg( InsRegMul('c0',arg1,8) , arg2 ); ByteLen:='2'; end; //mov R8-R8
end;
if isReg(arg1) then if isImm(arg2) then begin
if (RegLen='R16') then begin MashCode:=InsReg('b8',arg1)+cnvROM(arg2); ByteLen:='3'; end; //mov R16-Imm16
if (RegLen='R8') then begin MashCode:=InsReg('8a',arg1)+cnv(arg2); ByteLen:='2'; end; //mov R8-Imm8
end;
if (arg1='ax') then if (arg2='@data') then begin //mov ax-segname @Data
MashCode:='b8'+'0000';
ByteLen:='3';
//вспомогательный сегмент 9С05 для установки сегмента данных будет выведен:
ThisProgram.isDataSeg:=True; end;
if isReg(arg1) then if isData(arg2) then begin //mov Reg - data [si+n]
if cnvData(arg2)<>'*' then begin MashCode:='8b'+InsRegMul('44',arg1,8)+cnvData(arg2); ByteLen:='3'; end
else begin MashCode:='8b'+InsRegMul('04',arg1,8); ByteLen:='2' end;
end;
//послепроверка
if mashcode='' then ErrorControl:='<Неизв. аргумент>';
end;//---------------------------------------------------------------------/MOV
//int
if (oper='int') then if isImm(arg1) then if length(arg1)=3 then begin
MashCode:='cd'+cnv(arg1);
ByteLen:='2';
end;
//lea - varible
if (oper='lea') then if (arg1='si') then if (arg2<>'') then begin
MashCode:='be'+cnvROM(GetVarCodeByName(arg2));
ByteLen:='3';
end;
//sub
if (oper='sub') then begin
if isReg(arg1) then if isReg(arg2) then begin //sub R16-R16
MashCode:='2b'+InsReg( InsRegMul('c0',arg1,8) , arg2 );
ByteLen:='2'; end;
if isReg(arg1) then if isImm(arg2) then begin //sub R16-Imm16
if (arg1='ax') then begin MashCode:='2d'+cnvROM(arg2); ByteLen:='3'; end
else begin MashCode:='81'+InsReg('E8',arg1)+cnvROM(arg2); ByteLen:='4'; end;
end;
end;
//dec R16
if (oper='dec') then if isReg(arg1) then begin
MashCode:=InsReg('48',arg1);
ByteLen:='1';
end;
//rcr R16,R8 - imm8,cl
if (oper='rcr') then begin
if isReg(arg1) then if isImm(arg2) then begin
if (RegLen='R16') then begin
if arg2='01h' then begin MashCode:='d1'+InsReg('d8',arg1); ByteLen:='2'; end
else begin MashCode:='c1'+InsReg('d8',arg1)+cnv(arg2); ByteLen:='3'; end;
if (arg2='cl') then begin MashCode:='d3'+InsReg('d8',arg1); ByteLen:='2'; end
end;
if (RegLen='R8') then begin
if arg2='01h' then begin MashCode:='d0'+InsReg('d8',arg1); ByteLen:='2'; end
else begin MashCode:='c0'+InsReg('d8',arg1)+cnv(arg2); ByteLen:='3'; end;
if (arg2='cl') then begin MashCode:='d2'+InsReg('d8',arg1); ByteLen:='2'; end
end;
end;
end;
//jo
if (oper='jo') then begin
MarkTableWrite( arg1,'',inttostr(ComBytePos+2),inttostr(ComReadPos) );
MashCode:='70';
ByteLen:='2';
end;
//clc
if (oper='clc') then begin
MashCode:='f8';
ByteLen:='1';
end;
//Базовые команды:------------------------------------------------------------->
//mark: (место, куда осуществляется переход по метке)
if (mark<>'') then begin
MarksLinksTableWrite(mark,inttostr(ComBytePos));
exist:=true;
end;
END;
AnalysisCommand:=com;
end;
procedure TForm1.Exit1Click(Sender: TObject);
begin
Application.Terminate; //выход из программы
end;
procedure TForm1.FormCreate(Sender: TObject);
var pos:integer;
begin
//параметры программы
//изначально ни один из сегментов не присутствует
ThisProgram.isCodeSeg:=False;
ThisProgram.isDataSeg:=False;
//имена регистров 16разр:
SetLength(Reg16,20); //число возможных регистров
for pos := 0 to Length(Reg16)-1 do Reg16[pos]:='';
Reg16[0]:='ax';
Reg16[1]:='cx';
Reg16[2]:='dx';
Reg16[3]:='bx';
Reg16[6]:='si';
Reg16[7]:='di';
//имена регистров 8разр:
SetLength(Reg8,8); //число возможных регистров
for pos := 0 to Length(Reg8)-1 do Reg8[pos]:='';
Reg8[0]:='al';
Reg8[1]:='cl';
Reg8[2]:='dl';
Reg8[3]:='bl';
Reg8[4]:='ah';
Reg8[5]:='ch';
Reg8[6]:='dh';
Reg8[7]:='bh';
//установка указателя для считывания на начало программы
ComReadPos:=0;
//установка счетчика положения команд в байтах на начало
ComBytePos:=0;
//обнуление счетчика для записи переменных в сегмент даных
DataBytes:=0;
//таблица меток
marks.RowCount:=1;
marks.Cells[0,0]:='Имя метки';
marks.Cells[1,0]:='Метка';
marks.Cells[2,0]:='Вызов метки';
marks.Cells[3,0]:='Строка';
//таблица переменных
varibles.RowCount:=1;
varibles.Cells[0,0]:='Имя';
varibles.Cells[1,0]:='Адрес';
//таблица ссылок меток
markslinks.RowCount:=1;
markslinks.Cells[0,0]:='Имя';
markslinks.Cells[1,0]:='Метка';
ErrorControl:=''; //стирание сообщений об ошибках
end;
procedure TForm1.SaveButtonClick(Sender: TObject);
var txtfile:textfile; strhex:string; pos:integer;
begin
//объединение сегментов
strhex:=Title.Text+CodeSeg.Text;
if ThisProgram.isDataSeg then strhex:=strhex+'9c0500c801550140';
strhex:=strhex+DataSeg.Text+EndFile.Text;
strhex:=ViewOnlyHex(strhex);
//запись - подготовка
assignfile(txtfile,'program.txt');
rewrite(txtfile);
//преобразование в символ и запись
pos:=1; while (pos<=length(strhex)) do begin
write(txtfile,NexStrToStr(copy(strhex,pos,2)));
pos:=pos+2;
end;
closefile(txtfile);
//сообщение об успешном сохранении
MessageBox(0, 'Объектный файл сохранен', 'Успех', +mb_Ok +mb_ICONINFORMATION);
end;
procedure TForm1.CreateObjFileClick(Sender: TObject);
begin
//смещения прибавляемые к записям в объектном файле (+2 +4 +8)- зависят от длины след за них добавочных записей
//формирование заголовка
Title.Text:=AddControlByte('80'+IntToHexStr(length(FileName.Text)+2)+'000b'+StrToHexStr(FileName.Text))+#13#10+
AddControlByte('88'+IntToHexStr(length(CmplName.Text)+4)+'0000001c'+StrToHexStr(CmplName.Text))+#13#10+
AddControlByte('88'+IntToHexStr(length(FileName.Text)+8)+'0040e95c06893c0b'+StrToHexStr(FileName.Text))+#13#10+
'88 03 00 40 e9 4c'+#13#10+
'96 02 00 00 68'+#13#10+
'88 03 00 40 a1 94'+#13#10+
'96 0c 00 05 5f 54 45 58 54 04 43 4f 44 45 96'+#13#10+
'98 07 00 48'+IntToHexStr(ComBytePos+4)+'00 02 03 01 05'+#13#10+
'96 0c 00 05 5f 44 41 54 41 04 44 41 54 41 c2'+#13#10+
'98 07 00 48 00 00 04 05 01 0f'+#13#10+
'96 0d 00 05 53 54 41 43 4b 05 53 54 41 43 4b 67'+#13#10+
'98 07 00 74 00 01 06 07 01 de'+#13#10+
'96 08 00 06 44 47 52 4f 55 50 8b'+#13#10+
'9a 06 00 08 ff 03 ff 02 55'+#13#10+
'88 04 00 40 a2 01 91';
//формирование кодового сегмента
CodeSeg.Text:='a0'+IntToHexStr(ComBytePos+4)+'00010000'+ViewOnlyHex(MashCode.Text);
CodeSeg.Text:=AddControlByte(CodeSeg.Text);
//формирование сегмента данных
DataSeg.Text:='a0'+IntToHexStr(DataBytes+4)+'00020000'+ViewOnlyHex(MashData.Text);
DataSeg.Text:=AddControlByte(DataSeg.Text);
end;
procedure TForm1.ClearCodeButtonClick(Sender: TObject); //очистка поля для ввода кода прогр.
begin
Code.Clear;
end;
procedure TForm1.exeAllClick(Sender: TObject);
begin
while ComIs<>'EOF' do begin
ComExe;
ComNext;
end;
end;
procedure TForm1.exeOneClick(Sender: TObject);
begin
if ComIs<>'EOF' then begin
ComExe;
ComNext;
end;
end;
procedure TForm1.modifadressClick(Sender: TObject);
begin
AddLinksInMarkers; //пересылка всех меток из таблицы меток в таблицу поправок
ModifyMarkAdress; //рассчет смещений и добавление их к командам перехода
end;
end.
Приложение: Графическая оболочка программы - компилятора:
Рис. 1а Процесс распознавания команд из исходного текста
Рис. 2а Процесс формирования заголовка, сегментов и конца объектного файла
Размещено на http://www.allbest.ru
...Подобные документы
Задачи трансляторов, характеристика их видов. Этапы и функции основных фаз процесса компиляции. Описание используемых директив и команд ассемблера, алгоритмов, таблиц. Листинг программы. Алгоритм работы программной реализации разрабатываемого компилятора.
курсовая работа [1,3 M], добавлен 24.06.2013Принцип работы транслятора. Исследование формата данных объектного файла шестнадцатиразрядной системы DOS для последующего преобразования его в файл программы. Используемые директивы и команды ассемблера. Алгоритмы программы и таблицы компилятора.
контрольная работа [35,9 K], добавлен 07.07.2012Взаимосвязь стадий процесса проектирования сложных программных систем. Создание компилятора подмножества языка высокого уровня (Pascal) на язык Ассемблера. Структура входных и выходных данных, алгоритмы их обработки. Рабочая документация программы.
курсовая работа [256,7 K], добавлен 27.07.2014Построение компилятора с языка высокого уровня как одного из элементов системы программирования. Разработка компилятора ассемблера, модификация базы данных исходного макета. Загрузчик, эмулятор, отладчик. Использование Flex и Bison для программирования.
курсовая работа [599,0 K], добавлен 04.11.2014Функции компилятора как системной обрабатывающей программы. Этапы компиляции: анализ и синтез. Разработка лексического анализатора. Алгоритм и программа лексического анализа. Реализация двухфазного компилятора. Описание логической структуры программы.
курсовая работа [310,4 K], добавлен 26.03.2010Структура, классификация и требования к реализации компилятора. Проектирование и реализация анализирующей части компилятора языка С++. Способы реализации лексического анализа. Алгоритм работы синтаксического анализатора. Принципы программной реализации.
курсовая работа [774,2 K], добавлен 26.01.2013Выбор режимов адресации, посредством которых будет осуществлен доступ к данным. Этапы создания программы. Характеристика таблицы символов и полученного файла листинга. Анализ изменения состояния регистра IP при выполнении команд JMP, Jcc, LOOPx.
курсовая работа [4,9 M], добавлен 25.03.2012Разработка анализирующей части компилятора для выполнения проверки исходной программы на соответствие грамматике языка, правилам семантики и построения внутреннего представления. Описание анализаторов: лексического, синтаксического и семантического.
контрольная работа [704,9 K], добавлен 01.02.2013Назначение, принципы и методы построения таблиц идентификаторов. Метод простого рехэширования с помощью произведения. Назначение лексического анализатора. Таблица лексем и содержащаяся в ней информация. Построение лексических анализаторов (сканеров).
курсовая работа [703,1 K], добавлен 08.02.2011Строение схемы микропроцессора: все устройства, необходимые для приема из памяти, хранения, и выполнение команд, заданных согласно варианту режима адресации. Описания языка Ассемблера и его функции. Основные функции макропроцессора, варианты построения.
курс лекций [44,1 K], добавлен 06.03.2009Разработка транслятора упрощенного языка ассемблера. Преобразование файла в мнемокодах в файл, содержащий объектный двоичный код. Анализ набора команд. Выбор формата ассемблерной команды. Методика определения типа операнда. Формирование строки листинга.
курсовая работа [189,2 K], добавлен 14.02.2016Типы команд, синтаксис ассемблера и код операции, по которому транслируется команда. Команды вычисления и непосредственной пересылки данных между регистрами. Поле для определения операции вычисления. Управление последовательностью выполнения программы.
реферат [29,1 K], добавлен 13.11.2009Особенности ассемблера - машинно-ориентированного языка низкого уровня, применяемого для создания простых приложений. Связывание программ на разных языках. Типичный формат записи команд, инструкции и директивы языка ассемблера. Разработка игры "Змейка".
курсовая работа [215,0 K], добавлен 20.07.2014Создание приложения к реляционной базе данных "Личная фонотека". Исследование предметной области, выбор языка программирования и компилятора. Проектирование функциональности, структура программы, использованные алгоритмы; взаимодействие с пользователем.
курсовая работа [613,5 K], добавлен 29.12.2015Организация таблицы идентификаторов, ее содержание и назначение. Метод бинарного дерева и цепочек. Проектирование лексического анализатора и схема распознавателя. Построение дерева вывода, синтаксический анализатор. Анализ результатов работы программы.
курсовая работа [1,0 M], добавлен 25.12.2014Организация центрального процессора. Подключение интерфейсных программируемых БИС. Методы адресации и примеры команд. Программирование таймера и контроллера прерываний. Программная модель микропроцессорной системы. Программирование на языке ассемблера.
реферат [82,6 K], добавлен 05.12.2010Описание и принцип действия программы-отладчика микроконтроллера I8051 (К1816ВЕ51), предназначенной для программирования микроконтроллера на уровне языка ассемблера. Компиляция программы в объектный код и специфика тестирования разработанной программы.
реферат [21,1 K], добавлен 04.12.2010Общее описание и особенности использования программы, предназначенной для определения нечетных чисел, находящихся в массиве чисел. Листинг и методы оптимизации данной компьютерной программы. Источники оптимизации кода, описание выполненных команд.
лабораторная работа [17,4 K], добавлен 25.03.2011Процесс трансляции программы на языке ассемблера в объектный код. Разработка интерфейса для взаимодействия и связи программ. Понятие компиляции. Структура модели микропроцессора. Пример структуры двухбайтной команды. Арифметическо-логичесткие операции.
дипломная работа [3,3 M], добавлен 26.11.2012Разработка устройства управления процессора для выполнения команд сложения, вычитания и поразрядного логического "или", с использованием способов адресации операндов: регистр-регистр, регистр - непосредственно операнд, регистр - прямая адресация памяти.
курсовая работа [72,8 K], добавлен 21.11.2011