Метод parseRA(String[] ops, int bk)
Метод формирует первый байт так же, как и метод parseR, а значение второго байта устанавливается равным av = setAddrValue(ops[2],Asm.pAddr). Получается, в командах типа RA старшие четыре бита - команда, затем младшие четыре разряда первого байта - первый регистр, а значение второго байта - адрес.
В качестве результата возвращается
сформированный инфопакет.
7.3 Класс InfoBag
Класс, отвечающий за создание и формирование пакета как объекта. Класс имеет следующие поля: char lineType, ListingLine listline DiagLine diagline, BinCom bincom. Поля этого класса являются объектами классов ListingLine, DiagLine, BinCom.
Класс имеет
конструктор
с
параметрами
InfoBag (ListingLine listline, DiagLine diagline, BinCom bincom). Передаваемые
объекты конструктор соответственно записывает в поля объекта, тем самым
формируя инфопакет с заданными в параметрах данными.
7.4 Класс ListingLine
Класс отвечает за строку листинга инфопакета. Класс содержит следующие поля: String lineNo - номер строки, String comAddress - адрес размещения команды, String byteOne - первый байт комады, String byteTwo - второй байт команды, errMark - метка ошибки, String srcLine - копия исходной строки.
Имеет конструктор без параметров, который инициализирует объект с пустыми значениями полей класса.
Так же имеет конструктор с параметрами ListingLine( int lno, int ad, int k1, int k2, String err, String line). Полю lineNo присваивается значение lno, с использованием формата: действительное число с четырьмя знаками. Если параметр ad<0, полю comAddress присваивается значение " ххх ". В противном случае в переменную comAddress записывается отформатированное значение ad. Далее, если значение переменных k1 и k2 больше нуля, то переменные byteOne и byteTwo заполняются этими значениями соответственно. Если длина какого-то параметра будет меньше нуля, то соответственное поле заполнится “xx ” строкой. Значение поля errMark устанавливается равным первому символу строки err, передаваемой в качестве параметра. Переменной srcLine присваивается значение переменной line.
Класс содержит перегруженный метод toString,
который формирует и возвращает String-представление
объекта класса ListingLine.
Метод возвращает строку, состоящую из последовательно соединенных полей
объекта.
7.5 Класс BinCom
Класс отвечает за формирование байтов бинарного файла. Класс имеет поля int len - длина команды в байтах, int addr - адрес первого байта команды в памяти, byte1, byte2 - первый и второй байты команды, int p - признак команды, или директива
Класс содержит конструктор без параметров BinCom()
и конструктор с параметрами (int
l, int
pd, int
a, byte
b1, byte
b2). Параметры
последнего конструктора записываются в соответствующие поля объекта, тем самым
создавая объект с заданными параметрами.
7.6 Класс DiagLine
Класс, описывающий строку диагностики инфопакета.
Класс инициализирует статический массив строк-ошибок ErrorMess[]. Имеет одно единственное поле: String Line.
В классе существует два конструктора - пустой DiagLine() и с параметрами DiagLine (int ln, String msg). Передаваемые параметры в соответствии с форматом ("%03d", ln) записываются в поле line.
В классе определён перегруженный метод toString, возвращающий String-представление объекта класса DiagLine. В качестве результата метод возвращает строку line.
8. Отладка и тестирования программы
В качестве тестовых примеров будет предложена
совокупность команд - текстовый файл, содержащий программу на ассемблере -
которая содержит допустимые записи каждой команды таблицы ассемблера, а так же
некоторые заведомо неверные записи команд. Ошибка так же будет находиться во
всевозможных местах - мнемонике команды, операнде-регистре, операнде-адресе,
операнде константе. Тестовая программа не является реально решаемой задачей.
Она содержит совокупность всевозможных записей команд для отладки программы.
8.1 Исходные данные ( файл Src.txt)
ORG 10H;R0,25H;R0,26H;R10,27H;
NOTR R15,29H;один два три31H;один два три; ORG 25H;30H;31H;0H;245H;24;R0,45H;5,39H;R15,45;
8.2 Файл
листинга
(List.txt)
Листинг
1 010 хх хх ORG 10H;
2 010 d0 25 LOAD R0,25H;
3 012 20 26 ADR R0,26H;
4 014 ea 27 SAVE R10,27H;
5 016 1f хх NOTR R15,29H;один два три
6 017 70 31 JZ 31H;один два три
7 019 b0 хх CLF ;
8 025 хх хх ORG 25H;
9 025 30 хх DATA 30H;
10 026 31 хх DATA 31H;
11 027 00 хх DATA 0H;
13 ххх хх хх -DaTA 245H;
14 ххх хх хх -DATA 24;
15 ххх хх хх -LOD R0,45H;
16 ххх хх хх -ADR 5,39H;
17 ххх хх хх -SAVE R15,45
19 ххх ff хх END;
.3 Файл диагностики(Diag.txt)
Диагностика
DaTA 245H;
неверная мнемоника
DATA 24;
неправильно задан регистр(адрес)
LOD R0,45H;
неверная мнемоника
ADR 5,39H;
Первый операнд: неправильно задан регистр(адрес)
SAVE R15,45
Второй операнд: неправильно задан регистр(адрес)
.4 Файл с объектным двоичным кодом(binary.bin)
Данная последовательность команд проверяет
правильность работы всех ветвей программы, связанных с обработкой правильных
команд (методы parseLine,
parseR, parseZ,
parseRA, parseA,
setAddrValue, setRegValue,
findCom класса SourceLine,
а так же классы InfoBag,
ListingLine, DiagLine,
BinCom и Asm).
Заключение
В ходе курсовой работы были освоены навыки
работы с ассемблером, а так же укреплены усвоенные навыки программирования.
Была разработана программа-ассемблер, которая переводит мнемокод в объектный
код.
Список литературы
1.
Ноутон П. Java 2: [пер. с англ.]/П.Ноутон,
Г.Шилдт. - СПб.: БХВ-Петербург, 2014.
- 1072 с.
Приложение
Текст программы
Класс Asmjava.io.*;java.util.regex.*;class Asm {
static int acom = 0; //адрес команды
static BufferedReader src = null; //поток для исходной программы
static PrintWriter list = null; //поток для листинга
static PrintWriter diag = null; //поток для диагностики
static RandomAccessFile bin = null; //поток для двоичных команд
static Pattern pAddr; //скомпилированное рег.выр. для адреса
static Pattern pReg; //скомпилированное рег.выр. для регистра
static String[ ] PRCOMTAB = { //команды микроЭВМ
"ILR 0000 1 P R",
"NOTR 0001 1 P R",
"ADR 0010 2 P RA",
"CLR 0011 1 P R",
"ONR 0100 2 P RA",
"ANR 0101 2 P RA",
"XNR 0110 2 P RA",
"JZ 0111 2 P A",
"JL 1001 2 P A",
"JMP 1010 2 P A",
"CLF 1011 1 P Z",
"DOP 1100 1 P R",
"LOAD 1101 2 P RA",
"SAVE 1110 2 P RA",
"CMP 1111 2 P RA",
"ORG XXXX X O ",
"DATA XXXX 1 D",
"END XXXX X E"
};
static String[ ] prCom; //мнемоника
команд
микроЭВМ
-1-й
столбец
табл.
1
static { //статический инициализатор таблицы prCom
pAddr = Pattern.compile ( "^[0-9a-fA-F]{1,2}[hH]$" );
pReg = Pattern.compile ( "^[Rr](([0-9])|([1][0-5]))$" );
prCom = new String[PRCOMTAB.length];
for (int i = 0; i < PRCOMTAB.length; i++) {
prCom[i] = PRCOMTAB[i].substring(0, PRCOMTAB [ i ].indexOf(' '));
}
}
public static void main(String[ ] args) throws IOException {
String srcFile = "Src.txt"; //исходная программа
String listFile = "List.txt"; //листинг
String binFile = "binary.bin"; //двоичный код
String diagFile = "Diag.txt"; //диагностика
String line; //строка исходного файла
int num = 0; //номер строки файла
SourceLine sl;
ListingLine ll;
DiagLine dl;
BinCom bc;
//действия по открытию файлов
try { //если файлы нельзя открыть - исключение и окончание работы
src = new BufferedReader(new FileReader(srcFile));
list = new PrintWriter(listFile);
list.println("Листинг");
diag = new PrintWriter(diagFile);
diag.println("Диагностика");
bin = new RandomAccessFile(binFile, "rw");
ll = new ListingLine();
dl = new DiagLine();
bc = new BinCom();
InfoBag infobag=null;
while (( line = src.readLine()) != null ) { num++; //прочли строку
sl = new SourceLine ( line, num );
try {
infobag = sl.parseLine(sl.words); //обработка строки
list.println (infobag.listline);
if (infobag.diagline != null )
diag.println(infobag.diagline); ( infobag.lineType ) {
case 'O': Asm.acom = infobag.bincom.addr;
bin.writeByte ( infobag.bincom.p );
bin.writeByte ( infobag.bincom.addr ); break;
case 'D': bin.writeByte ( infobag.bincom.p );
bin.writeByte (infobag.bincom.byte1);
Asm.acom+= infobag.bincom.len; break;
case 'P': bin.writeByte ( infobag.bincom.p );
bin.writeByte ( infobag.bincom.byte1 );
if (infobag.bincom.len == 2) { //если требуется второй байт
bin.writeByte ( infobag.bincom.p );
bin.writeByte ( infobag.bincom.byte2 );
}
Asm.acom+= infobag.bincom.len; break;
case 'E': bin.writeByte ( infobag.bincom.p );
default:
}
}
catch (Exception e) { }
}//while
}//try
finally { //закрытие потоков
if ( src != null) { src.close ( ); }
if ( list != null) { list.close ( ); }
if ( diag != null) { diag.close ( ); }
if (bin !=null) {bin.close( ); }
}//finally
}
}
Класс SourceLinejava.io.*;java.util.*;java.lang.*;java.util.regex.*;class SourceLine { // Класс : строка исходной программы
String sourceLine; //исходная строка, заполняется конструктором
String myLine; //исходная строка без пробелов слева и справа
String[ ] words; //части строки - слова
int lineNumber; //номер строки
char lineType; //C-комментарий, A,O,D,E-команды ассемблера,
//P-команда процессора, X - неизвестный тип
int nAsm; //номер команды в таблице команд ассемблера
int nProc; //номер команды в таблице команд микроЭВМ
public SourceLine(String l, int n) { // конструктор
sourceLine = new String(l); // Задается сама строка
lineNumber = n; // и ее номер,
myLine = sourceLine.trim(); // удаляются пробелы слева и справа,
words = myLine.split("(\\s+)|[,;]"); // строка разбивается на слова
}
public InfoBag parseLine(String[ ] wo) { //wo - массив слов строки
InfoBag info = null; DiagLine dil = null; ListingLine lil = null;
lineType = 'X'; //а вдруг определить не удастся
String[ ] ww = null; //для частей из таблицы команд
if ( wo.length == 0) lineType = 'C';//пустая строка
if ( wo [ 0 ].equals("") ) lineType = 'C';
if ( wo [ 0 ].charAt ( 0 ) == ';') lineType = 'C';
else if ((nProc = findCom(wo[0], Asm.prCom)) >= 0) //поиск команды в та
{ ww = Asm.PRCOMTAB [ nProc ].split ( "\\s+" ) ;
lineType = ww [ 3 ].charAt ( 0 );//поле с номером 3 в PRCOMTAB - тип
}
switch (lineType) {//обработка команды согласно ее типу
case 'C': info = parseComment (); info.lineType = 'C'; break;
case 'O': info = setOrg ( wo ); info.lineType = 'O'; break;
case 'D': info = setData( wo ); info.lineType = 'D'; break;
case 'E': info = setEnd( wo ); info.lineType = 'E'; break;
case 'P': //команды микроЭВМ
String kod = ww [ 1 ]; //поле 1 в PRCOMTAB - код команды
int binaryKod = Integer.parseInt ( kod, 2 ); //получен код операц
String format = ww [ 4 ]; //выбор поля 4 - формата команды
if (format.equals ("RA" )) info = parseRA ( wo, binaryKod );
if (format.equals ( "Z" )) info = parseZ ( wo, binaryKod);
if (format.equals ( "A" )) info = parseA ( wo, binaryKod);
if (format.equals ( "R" )) info = parseR ( wo, binaryKod);
info.lineType = 'P'; break; //строка - команда микроЭВМ
default: {
dil = new DiagLine(lineNumber, sourceLine + "\n " + DiagLine.ErrorMess[1]);
lil = new ListingLine(lineNumber, -1, -1, -1,"-", sourceLine);
info = new InfoBag(lil,dil,null); info.lineType = 'X';
}
}
return info;
}InfoBag parseComment(){
return new InfoBag (
new ListingLine ( lineNumber, -1, -1, -1, " ", sourceLine), null, null );
}int findCom ( String w, String [ ] com ) { //прямой поиск w в com
for ( int i = 0; i < com.length; i++ ) {
if ( w.equals( com [ i ] ) )
return i;
}
return -1;
}
private InfoBag setOrg ( String[ ] ops) { //параметр - массив слов строки
DiagLine dil = null;
ListingLine lil = null;
BinCom bic = null;
int av = -3;
if (ops.length > 1) av = setAddrValue ( ops[1], Asm.pAddr );
if (av>= 0) {
lil = new ListingLine ( lineNumber, av, -1, -1," ", sourceLine);
bic = new BinCom(1, 1, av,(byte)0,(byte)0);
}
else {
lil = new ListingLine( lineNumber, -1, -1, -1, "-", sourceLine);
dil = new DiagLine( lineNumber, sourceLine + "\n " + DiagLine.ErrorMess[-av]);
}
return new InfoBag ( lil, dil, bic);
}InfoBag setData(String[ ] ops){
DiagLine dil = null;
ListingLine lil = null;
BinCom bic = null;
int av = -3;
if (ops.length > 1) av = setAddrValue ( ops[ 1 ], Asm.pAddr );
if (av>= 0) {
lil = new ListingLine ( lineNumber, Asm.acom, av, -1, " ", sourceLine );
bic = new BinCom (1, 2, Asm.acom, (byte) av, (byte) 0);
}
else {
lil = new ListingLine ( lineNumber, -1, -1, -1, "-", sourceLine);
dil = new DiagLine ( lineNumber, sourceLine + "\n " + DiagLine.ErrorMess[-av]);
}
return new InfoBag ( lil, dil, bic);InfoBag setEnd(String [] ops) {
DiagLine dil = null;
ListingLine lil = null;
BinCom bic = null;
int k=(7<<5)|(7<<2)|3;
return new InfoBag ( lil = new ListingLine ( lineNumber, -1, k, -1, " ", sourceLine),
null,
bic = new BinCom (1, k, Asm.acom, (byte)0, (byte) 0) );
}InfoBag parseRA(String [ ] ops, int bk ) {//формат RA - регистр, адрес
int k = bk; int rv, av;
DiagLine dil = null;
ListingLine lil = null;
BinCom bic = null;
if ( ops.length > 1) { rv = setRegValue(ops[1], Asm.pReg);
}
else { rv = -3; } //операнда нет
k = (bk << 4) | ( rv | 0 );
if (ops.length > 2) { av = setAddrValue(ops[2],Asm.pAddr);
}
else { av = -3; } //операнда нет
if ((rv>= 0) && (av>= 0)) {
lil = new ListingLine ( lineNumber, Asm.acom, k, av, " ",sourceLine);
bic = new BinCom ( 2, 2, Asm.acom, (byte)k, (byte)av);
}
else { //ошибка в 1-м или 2-м операнде
String xx = new String();
String newString=new String();
if (rv<0) {
xx+= new String("Первый операнд: " + DiagLine.ErrorMess[-rv]);
newString="\n";//есть первая строка
}
if (av<0) {
xx+=newString;
xx+= new String("Второй операнд: " + DiagLine.ErrorMess[-av]);
}
lil = new ListingLine( lineNumber, -1, -1, -1, "-",sourceLine);
dil = new DiagLine( lineNumber, sourceLine + "\n" + xx);
}
return new InfoBag( lil, dil, bic);
}InfoBag parseA(String [ ] ops, int bk ) {//формат A - адрес
int k = bk; int av;
DiagLine dil = null;
ListingLine lil = null;
BinCom bic = null;
if ( ops.length > 1) { av = setAddrValue(ops[1], Asm.pAddr);
}
else { av = -3; } //операнда нет
k = (bk << 4);
if (av>= 0) {
lil = new ListingLine ( lineNumber, Asm.acom, k, av, " ",sourceLine);
bic = new BinCom ( 2, 2, Asm.acom, (byte)k, (byte)av);
}
else { //ошибка в 1-м или 2-м операнде
String xx = new String();String newString=new String();
xx+= new String ("Oперанд: " + DiagLine.ErrorMess [ -av ] );
lil = new ListingLine( lineNumber, -1, -1, -1, "-",sourceLine);
dil = new DiagLine( lineNumber, sourceLine + "\n" + xx);
}
return new InfoBag( lil, dil, bic);
}InfoBag parseZ (String[ ] ops, int bk ) {//формат Z - без операндов
DiagLine dil = null;
ListingLine lil = null;
BinCom bic = null;
int k = (bk << 4); // 4 бита - код операции,
lil = new ListingLine(lineNumber, Asm.acom, k, -1, " ",sourceLine);
bic=new BinCom ( 1, 2, Asm.acom, ( byte ) k,(byte)0);
return new InfoBag ( lil, dil, bic );
}InfoBag parseR ( String [ ] ops, int bk ) { //формат R
int k=bk; int rv;
DiagLine dil = null;
ListingLine lil = null;
BinCom bic = null;
if (ops.length > 1) { rv = setRegValue(ops[1], Asm.pReg);
}
else { rv = -3;}
k = (bk << 4)|(rv | 0);
if ( rv>= 0 ) { // ошибок в операнде нет
lil = new ListingLine(lineNumber, Asm.acom, k, -1, " ",sourceLine);
bic=new BinCom ( 1, 2, Asm.acom, ( byte ) k, ( byte )0);
}
else { // в операнде есть ошибки
String xx =new String ("Первый операнд: "+DiagLine.ErrorMess [-rv] );
lil = new ListingLine ( lineNumber, -1, -1, -1, "-",sourceLine );
dil = new DiagLine ( lineNumber, sourceLine + "\n" + xx ) ;
}
return new InfoBag ( lil, dil, bic );
}int setRegValue(String w,Pattern pr) {// w - слово, содержащее операнд-регистр
if (( w == null ) || ( w.length()==0 )) { val= -3;
}
else {
if ( pr.matcher(w).matches( ) ) {
val = Integer.parseInt ( w.replaceAll("[Rr]",""));
val = (val | 0);
}
else { val = -2; }
}
return val;
}int setAddrValue( String w,Pattern pr) {
int val = 0;
if ((w == null) || (w.length() == 0)) { val= -3;
}
else {
if ( pr.matcher(w).matches ( ) ) {
val = Integer.parseInt ( w.substring ( 0, w.length( ) - 1), 16);
}
else { val= -2; }
}
return val;
}
}
Класс InfoBag
public class InfoBag { //информационный пакет
char lineType; //тип строки в исходном тексте
ListingLine listline; //строка листинга
DiagLine diagline; //строка диагностики
BinCom bincom; //двоичный код, соответствующий строке
public InfoBag (ListingLine listline, DiagLine diagline ,BinCom bincom) {
this.listline = listline;
this.diagline = diagline;
this.bincom = bincom;
}
}
Класс ListingLineclass ListingLine {
String lineNo; //номер строки
String comAddress; //адрес размещения кода команды
String byteOne; //первый байт команды
String byteTwo; //второй байт команды
String errMark; // ‘’-‘’ отметка строки с ошибкой
String srcLine; //копия исходной строки
public ListingLine( ) { lineNo = new String(); byteOne = new String();
byteTwo = new String(); comAddress = new String();
srcLine = new String();
}
public ListingLine(int lno ,int ad, int k1, int k2, String err, String line){
lineNo = new String(String.format("%4d ", lno));
if (ad<0) comAddress = new String(String.format("ххх "));
else comAddress = new String(String.format("%03x ",ad));
if (k1<0 ) byteOne = new String(String.format("хх "));
else byteOne = new String(String.format("%02x ",k1));
if (k2<0 ) byteTwo = new String(String.format("хх "));
else byteTwo = new String(String.format("%02x ",k2));
errMark = err.substring(0, 1);
srcLine = line;String toString() {
return new String(lineNo+comAddress+byteOne+byteTwo+errMark+srcLine);
}
}
Класс BinComclass BinCom {
int len;
int addr;
byte byte1, byte2;
int p;
public BinCom ( ) {
len= addr= byte1= byte2=(byte)0;
}
public BinCom ( int l, int pd, int a, byte b1,byte b2 ) {
len = l; addr = a; p=pd;
byte1 = b1; byte2 = b2;
}
}
Класс DiagLineclass DiagLine {