Команды типа Р с типом операнда RА - двухбайтовые команды. Поскольку длина самой команды - четыре бита, а длина операнда - четыре бита, то необходимо использовать минимум два байта для записи такой команды. Распределим информацию в байтах таким образом: старшие четыре разряда первого байта - бинарный код команды, младшие четыре разряда первого байта - первый операнд, второй байт - операнд адрес.
Первые байт формируется точно так же, как и в случае типа операнда R. Значение второго байта заполняется адресом. Строка листинга: номер строки, адрес команды, первый байт, второй байт, исходная строка. Бинарная "строка": длина команды - 2, признак команды, первый байт, второй байт.
Для данного типа строки возможны две ошибки -
ошибка в первом операнде и ошибка во втором операнде. Если значение операнда
отрицательно, формируется строка диагностики: "Первый"/"Второй"
+" операнд:" + краткое описание типа ошибки.
Тип строки P, тип операнда A (метод parseA)
|
1 байт |
2 байт |
Мнемокод и операнд |
|
0111---- |
AAAAAAAA |
JZ адрес |
|
1001---- |
AAAAAAAA |
JL адрес |
|
1010---- |
AAAAAAAA |
JMP адрес |
Строки типа Р с типом операнда A являются двухбайтовыми командами. Старшие четыре разряда, как и в остальных командах типа Р, содержат байт-код команды, младшие четыре разряда будут являться нулями. Остальные восемь разрядов операнда адреса будут храниться во втором байте.
Первый байт формируется как и в предыдущих случаях - поразрядным сдвигом байт-кода команды на четыре. Строка листинга формируется следующим образом: номер строки, адрес команды, первый байт, второй байт, исходная строка. Бинарная "строка": Длина команды - 2, первый байт, второй байт.
В случае, если допущена ошибка в записи операнда, формируется строка листинга: номер строки, признак ошибки и исходная строка. Строка диагностики: номер строки, исходная строка, символ перехода на новую и краткое описание типа ошибки. Бинарная часть инфопакета - null.
Алгоритм поиска(выделения) адреса
Задача поиска адреса должна давать следующие результаты: если операнд написан верно - его значение, если не верно - код ошибки (отрицательное число).
Методу в качестве параметров передаётся слово-операнд из исходной строки и шаблон записи адреса. Если переданное слово пусто (null, или длина слова равна 0), то результат -3(операнд отсутствует). Если слово не удовлетворяет шаблону, то результат равен -1 (номер ошибки, соответствующий неверной мнемонике). Если слово удовлетворяет шаблону, производится идентификация кода - считывание признака системы счисления. Если на этапе преобразования возникнет исключение (Exception), то результатом будет -2(неверно задан регист(адрес)). Если ошибки не возникло, метод возвращает значение операнда.
Алгоритм поиска(выделения) регистра
Задача аналогичная задаче поиска адреса за исключением положения, касающегося непосредственно поиска значения регистра. Значения регистров лежат в интервале от 0 до 15. из исходной строки выделяется непосредственно значение регистра, и если он задан числом - возвращается это число. Принцип формирования ошибок типа -1 и -3 аналогичен принципу в задаче поиска адреса. Формирование ошибки типа два происходит в случае, если операнд не является числом 0-15.
Попробуем описать алгоритм работы программы опустившись до уровня решения подзадач.
Первым шагом алгоритма является создание потоков
считывания и записи. Далее считывается строка если она не равна нулю,
выполняется её обработка: решается задача определения типа строки. Если тип
строки C, O,
D, E
- решается задача формирования инфопакета для соответствующего типа строки.
Если тип строки P - находится
тип операнда команды и решается соответствующая задача формирования инфопакета.
Сформированные строки инфопакета выводятся в соответствующие файлы. Считывается
следующая строка. И так до тех пор, пока не будет обработана строка типа E
или строка не будет пустой (конец текстового файла). Потоки считывания и записи
закрываются.
4. Описание входных и выходных данных
Входные данные:
Текстовый файл, содержащий программу на ассемблере. Команды в программе имеют длину 1 или 2 байта. Биты 4-7 первого байта содержат код команды в соответствии с таблицей команд. Биты 0-3 и второй байт используются для задания адреса памяти, где находится константа или операнд.
Все операции производятся над операндами,
находящимися в памяти или стеке. Результат может быть сохранен в памяти или
стеке. Каждая строка должна содержать не более одной команды. Мнемокод
отделяется от операнда последовательностью пробелов. Таблица допустимых команд:
|
Код |
Мнемокод и операнды |
|
0000 |
ILR регистр |
|
0001 |
NOTR регистр |
|
0010 |
ADR регистр,память |
|
0011 |
CLR регистр |
|
0100 |
ONR регистр, адрес |
|
0101 |
ANR регистр, адрес |
|
0110 |
XNR регистр, адрес |
|
0111 |
JZ адрес |
|
1001 |
JL адрес |
|
1010 |
JMP адрес |
|
1011 |
CLF |
|
1100 |
DOP регистр |
|
1101 |
LOADрегистр,адрес |
|
1110 |
SAVE регистр,адрес |
|
1111 |
CMP регистр, адрес |
В программе имеет значение регистр символа - он обязательно должен быть верхним.
Программа должна выполнять преобразование текстового файла в двоичный код (т.е. код команды и код адреса нахождения операнда).
Выходные данные:
При выполнении программы формируются 3 файла:
. Бинарный файл, который получается в результате трансляции команд данного текстового файла;
. Текстовый файл - файл-листинг, который содержит исходный текст, его кодировку и результаты трансляции.
. Файл диагностики. В этот файл выводятся сообщения об ошибках трансляции:
ошибка в написании имени команды
ошибка в написании операндов
отсутствие операндов
При выявлении ошибки формирование объектного
файла невозможно и выполнение программы прекращается, а в файле диагностики
выводится описание ошибки.
5. Анализ возможных ошибок
В результате ассемблирования может возникнуть ряд ошибок:
Неверные разделители(Отличный от запятой при разделении операндов, от пробела или Таb, при разделении мнемоники и операнда или операндов)
Неверная мнемоника команды, или её отсутствие
Несуществующий адрес
Отсутствие операнда у команды
Неверное написание операнда
Комментарии не отделены
6. Разработка программы
Программа имеет некоторые ограничения:-в каждой строке записывается только одна команда процессора;
команда содержит мнемонику операции, за мнемоникой следуют операнды;
после операндов можно расположить комментарий
если операнды есть, между мнемоникой и операндами должен быть по крайней мере один пробел;
комментарий начинается знаком «;», или
отделяется пробелом;
7. Описание программы
.1 Класс Asm
Является главным классом программы. Содержит инициализацию таблицы команд процессора, записи операндов-регистров и операндов-адресов, констант, потоков считывания и записи, переменной адреса команды acom. Имеет главный метод main, который нужно выполнить, чтобы запустить программу.
В качестве потока считывания исходного текста src.txt используется класс BufferedReader (FileReader). Для потоков записи файлов листинга и диагностики используется класс PrintWriter. Для формирования бинарного файла используется класс RandomAccessFile.
Массив String[] PRCOMTAB формируется в соответствии с таблицей команд процессора. Каждому элементу массива соответствует команда из таблицы команд. Команды не повторяются, каждая команда имеет уникальный мнемокод и двоичный код. Формат строки массива PRCOMTAB: мнемокод, двоичный код, длина команды, тип команды, тип операнда. Каждый элемент в строке должен быть отделён от соседнего пробелом.
Инициализация шаблонов записи операндов-адресов и операндов-регистров. Операнд адрес - это слово, которое в случае двоичного кода может иметь не более 8-ми битов. Может содержать любые символы шестнадцатеричной системы счисления (0-15) и обязательно заканчиваться на один из символов h,H.
Операнд-регистр - длиной не менее и не более трех символов .Первый символ - признак регистра, второй и третий символ - номер регистра. Для 16 регистров достаточно двух символов, чтобы указать каждый регистр. Регистр должен удовлетворять такому регулярному выражению: "^[Rr](([0-9])|([1][0-5]))$". Это значит что регистр должен начинаться с символов R или r и заканчиваться цифрой от 0 до 15.
Метод main(String[]
args) Является главным
исполняемым методом. Создаёт потоки считывания и записи, производит считывание
строк, вызывает метод обработки строки parseLine
и выполняет вывод инфопакета, сформированного в процессе обработки строки, в
файлы листинга и диагностики. После считывания строки, формирования инфопакета
и вывода строки диагностики, в зависимости от типа строки lineType,
выполняет следующие действия: если тип строки О (ORG-адрес)
- устанавливает значение acom,
равное значению адреса, хранящемуся в сформированном инфопакете, в его бинарной
части; если тип команды D
(DATA) - записывает в
бинарный файл адрес команды, выводит значение первого и второго байта,
увеличивает acom на bincom.len
(длину команды); P ( команда
процессора) - выводит адрес команды, значение первого байта, и если команда
двухбайтовая - выводит второй байт. Весь текст метода, начиная с считывания
строки заключен в блок try,
и в случае возникновения исключения, все потоки будут закрыты, а выполнение
программы остановлено.
7.2 Класс SourceLine
ассемблер транслятор двоичный код
Содержит основные методы обработки исходной строки: parseLine, parseComment, setOrg, setData, setEnd, parseRА, parseA, parseR, parseZ; а так же вспомогательные: setAddrValue, setRegValue, findCom. Основные методы в качестве результата возвращающают инфопакет, вспомогательные - формируют результаты вычисления подфункций.
Класс имеет следующие поля:
String sourceLine - исходная строка, формируется конструктором - считывается из файла Src.txt.
String myLine - исходная строка без пробелов слева и справа.
String[] words - части строки - слова.
int lineNumber - номер строки.
char lineType - тип строки.
int nProc - номер команды в таблице команд микроЭВМ
Метод parseComment(String line)
В качестве параметра методу передаётся исходная строка. Метод формирует инфопакет, бинарная и диагностическая части которого равну null. Строка листинга формируется следующим образом - конструктору ListingLine передается следующий набор параметров : (-1, -1, -1, -1, " ", line.substring(1,line.length())). Последний параметр - это строка без первого символа, т.е. без символа ";".
В качестве результата метод возвращает сформированный инфопакет.
Метод parseLine(String[] wo)
Метод определяет тип строки (X,C,O,D,E,P). Переменной lineType, в результате выполнения метода присваивается одно из этих значений в зависимости от содержания исходной строки.
В случае, если строка имеет тип P, переменной kod присваивается значение двоичного кода этой команды и в переменную format записывается 4-ое поле PRCOMTAB - формат команды (RA,R,A,Z). Каждому формату команды соответствует свой метод обработки строки. Для строки RA будет выполняться метод parserRA, для R - parseR. Для данной структуры метод parseRA не нужен. Но т.к. PRCOMTAB содержит команды формата A, необходимо определить метод parseA().
В случае, если тип строки X, формируется инфопакет ошибки.
Метод findCom(String w, String[] com) является вспомогательным служебным методом. Методу в качестве параметров передаётся строка w (первое "слово" исходной строки) и массив строк com (таблица мнемоник команд). Прямым поиском сравнивается w и элементы массива com. В качестве результата метод возвращает значение номера элемента массива com, которому соответствует w. Если такого соответствия не обнаружено, метод возвращает -1.
Метод setRegValue(String w, Pattern pr)
Так же является вспомогательным методом.
Методу в качестве параметра передается "слово" w, содержащее операнд регистр, вида R1 или r14. Метод проверяет длину строки w на наличие в нём символов (операнда). Если символов нет, переменной val присваивается значение -3, и при дальнейшей проверке этой переменной формируется инфопакет ошибки. Если строка w не удовлетворяет правилам записи строки, хранящиеся в Pattern pr, значение val устанавливается равным -2, что означает ошибку с кодом -2, т.е. неверная мнемоника.
Если значение слова больше нуля, и слово удовлетворяет правилам записи операнда-регистра, выполняется следующее: в переменную val записывается значение w, переведённое из той системы счисления, которое указано конечным символом слова w. Метод возвращает значение val.Если меньше возвращает -3.
Метод setAddrValue(String w, Pattern pr) повторяет метод setRegValue.
Метод setOrg(String[] ops)
В качестве параметра методу передается массив слов исходной строки. Метод формирует инфопакет. Строка листинга инфопакета формируется конструктором ListingLine с набором параметров (lineNumber, Asm.acom, av, -1," ", sourceLine). Строка бинарного файла создается c 1 байтом.
Метод setData(String[] ops)
В качестве параметра методу передается массив слов исходной строки. Метод формирует инфопакет. Строка листинга инфопакета формируется конструктором ListingLine с набором параметров ( lineNumber, Asm.acom, av, -1, " ", sourceLine ). Строка бинарного файла создается c 1 байтом. Метод setEnd( ) возвращает инфопакет со строкой листинга, строкой бинарного файла с 1 байтом. Метод parseZ(String[] ops, int bk) Метод возвращает инфопакет, содержащий информацию об обработке команды типа Z (команда типа Z - строка, не содержащая операндов).
В случае адекватных данных метод присваивает значению k, значение двоичного представления команды, которое передаётся ему в качестве параметра bk. Метод выполняет операцию поразрядного сдвига на четыре влево.
Метод parseR(String[] ops, int bk)
Почти аналогичен методу parseZ, за одним исключением. После формирования переменной k, равной bk и операции сдвига влево на четыре разряда, к переменной применяется операция порязрядного сложения переменной rv, значение которой устанавливается методом setRegValue(ops[1], Asm.pReg).
Конструктору бинарной строки передает один, первый байт.
Метод parseA(String[] ops, int bk)
Обрабатывает строку типа A. Строка типа А содержит команду операнд-адрес. Метод формирует переменную k так же, как и метод parseZ, только значением второго байта берет av, предварительно сформированное методом setAddrValue(ops[1], Asm.pAddr). Команды типа A - двухбайтовые.