Проектирование компилятора

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

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 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

Применение: 

Команда sub используется для выполнения вычитания целочисленных операндов или для вычитания младших частей значений многобайтных операндов.

4) RCR - Циклический сдвиг операнда вправо через флаг переноса.

Схема команды: 

rcr операнд,количество_сдвигов 

Назначение: операция циклического сдвига операнда вправо через флаг переноса cf.

Алгоритм работы:

сдвиг всех битов операнда вправо на один разряд; при этом младший бит операнда становится значением флага переноса cf;

одновременно старое значение флага переноса -- в операнд слева и становится значением старшего бита операнда;

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

Состояние флагов после выполнения команды:

11

00

OF

CF

?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

Применение: 

Команда 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

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.