Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
СиППО.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
362.72 Кб
Скачать

Модуль Assembler.

interface

uses

AVLTree, SysUtils, macroGen;

type

TComLine = record

SymbName,

MOpCode,

Opd1, Opd2: string;

end;

type

TOpCode = record

Name,

Code: string;

Len: byte;

IsDir: boolean;

Opd1, Opd2: byte;

end;

type

TErrTypes = (eNoErr, eSTART_MISSING, eEND_MISSING, eINCORRECT_OPCODE,

eDUP_SYMB_NAME, eINCORRECT_OPD, eSYMB_NAME_NOT_FOUND,

eTWO_MEM_OPD, eBAD_MARK_NAME);

type

TError = record

ErrType: TErrTypes;

StrNum: byte;

end;

const

NumOps = 8;

NumReg = 8;

MaxLines = 256;

MaxSymbNames = 256;

BytesPerBYTE = 1;

BytesPerWORD = 3;

oNONE = 1;

oREG = 2;

oVALUE = 4;

oEX_VALUE = 8;

oSYMB_NAME = 16;

oSTRING = 32;

MaxByteVal = $FF;

MaxWordVal = $FFFFFF;

MaxResBVal = $FF;

MaxResWVal = $55;

ErrText: array [TErrTypes] of string = ('',

'Не найдена точка входа START',

'Не найден конец программы END',

'Неверный код операции',

'Дублирование символического имени',

'Некорректный операнд',

'Символическое имя не найдено',

'Оба операнда - символические имена',

'Неверное имя метки');

RegName: array [0..NumReg - 1] of string = ('R1', 'R2', 'R3', 'R4', 'R5', 'R6', 'R7', 'R8');

var

OpCodeTable: array [0..NumOps - 1] of TOpCode = ((Name:'ADD'; Code:'01'; Len:3; IsDir:false; Opd1: oREG or oSYMB_NAME; Opd2: oREG or oSYMB_NAME or oVALUE),

(Name:'JUMP'; Code:'02'; Len:4; IsDir:false; Opd1: oSYMB_NAME; Opd2: oNONE),

(Name:'NOP'; Code:'03'; Len:1; IsDir:false; Opd1: oNONE; Opd2: oNONE),

(Name:'BYTE'; Code:'04'; Len:0; IsDir:true; Opd1: oEX_VALUE or oSTRING; Opd2: oNONE),

(Name:'WORD'; Code:'05'; Len:0; IsDir:true; Opd1: oEX_VALUE; Opd2: oNONE),

(Name:'START'; Code:'08'; Len:0; IsDir:true; Opd1: oVALUE; Opd2: oNONE),

(Name:'END'; Code:'09'; Len:0; IsDir:true; Opd1: oNONE or oVALUE; Opd2: oNONE),

(Name:'MOV'; Code:'0A'; Len:3; IsDir:false; Opd1: oREG or oSYMB_NAME; Opd2: oREG or oSYMB_NAME or oVALUE));

InputTable, TempTable: array [0..MaxLines - 1] of TComLine;

Output: array [0..MaxLines - 1] of string;

SymbNameTree: TAVLTree;

NumSymbNames,

NumLines: byte;

ProgLen: cardinal;

procedure FirstParse(InputTable: array of TComLine; var TempTable: array of TComLine;

SymbNameTree: TAVLTree; var NumSymbNames: byte; var Error: TError; NumComLines: byte;

var ProgLen: cardinal; var Header: string);

procedure SecondParse(TempTable: array of TComLine; var Output: array of string;

var Error: TError; SymbNameTree: TAVLTree; NumSymbNames: byte; NumComLines: byte);

implementation

function IsHexNum(Str: string): boolean;

var

i: byte;

begin

result := true;

if (Str <> '') then

begin

for i := 1 to Length(Str) do

begin

if ( not ((Str[i] >= '0') and (Str[i] <= '9')) or ((Str[i] >= 'A') and (Str[i] <= 'F'))) then

begin

result := false;

exit;

end;

end;

end else

begin

result := false;

exit;

end;

end;

function HexAddDec(Hex: string; Dec: cardinal; MaxDig: byte): string;

begin

if (Hex = '') then

Hex := '0';

Result := IntToHex(StrToInt('$' + Hex) + Dec, MaxDig);

end;

function HexMulDec(Hex: string; Dec: cardinal; MaxDig: byte): string;

begin

if (Hex = '') then

Hex := '0';

Result := IntToHex(StrToInt('$' + Hex) * Dec, MaxDig);

end;

function IsRegName(Name: string; var RegId: byte): boolean;

var

i: byte;

begin

Result := false;

for i := 0 to NumReg - 1 do

begin

if (Name = RegName[i]) then

begin

Result := true;

RegId := i + 1;

break;

end;

end;

end;

procedure FirstParse(InputTable: array of TComLine; var TempTable: array of TComLine;

SymbNameTree: TAVLTree; var NumSymbNames: byte; var Error: TError; NumComLines: byte;

var ProgLen: cardinal; var Header: string);

var

AddrCnt: cardinal;

i, j,

FoundIdx: byte;

IsFound,

IsStartFound, IsEndFound: boolean;

Len: word;

val: integer;

begin

Error.ErrType := eNoErr;

if (not tryStrToInt('$' + InputTable[i].Opd1, val)) then

begin

error.ErrType := eINCORRECT_OPD;

exit;

end;

AddrCnt := StrToInt('$' + InputTable[0].Opd1);

IsStartFound := false;

IsEndFound := false;

for i := 0 to NumComLines - 1 do

begin

if ((i > 0) and (InputTable[i].SymbName <> '')) then

begin

if (SymbNameTree.FindNode(InputTable[i].SymbName) = nil) then

begin

{ if (not isCorrectName(inputTable[i].SymbName, ASM_MARK_SYMBOL, ASM_MARK_FORBIDDEN_SYMBOLS)) then

begin

Error.ErrType := eBAD_MARK_NAME;

Error.StrNum := i;

exit;

end; }

SymbNameTree.AddNode(InputTable[i].SymbName, IntToHex(AddrCnt, 2 * BytesPerWORD));

end else

begin

Error.ErrType := eDUP_SYMB_NAME;

Error.StrNum := i;

exit;

end;

end;

IsFound := false;

for j := 0 to NumOps - 1 do

begin

if (InputTable[i].MOpCode = OpCodeTable[j].Name) then

begin

IsFound := true;

FoundIdx := j;

break;

end;

end;

if (IsFound) then

begin

if (OpCodeTable[FoundIdx].IsDir) then

begin

if (OpCodeTable[FoundIdx].Name = 'BYTE') then

begin

if (InputTable[i].Opd1[1] = 'c') then

Len := Length(InputTable[i].Opd1) - 3

else

Len := BytesPerBYTE;

end else

if (OpCodeTable[FoundIdx].Name = 'WORD') then

Len := BytesPerWORD

else

if (OpCodeTable[FoundIdx].Name = 'RESB') then

begin

if (not tryStrToInt('$' + InputTable[i].Opd1, val)) then

begin

Error.ErrType := eINCORRECT_OPD;

Error.StrNum := i;

exit;

end;

Len := BytesPerByte * StrToInt('$' + InputTable[i].Opd1);

end else

if (OpCodeTable[FoundIdx].Name = 'RESW') then

begin

if (not tryStrToInt('$' + InputTable[i].Opd1, val)) then

begin

Error.ErrType := eINCORRECT_OPD;

Error.StrNum := i;

exit;

end;

Len := BytesPerWord * StrToInt('$' + InputTable[i].Opd1);

end else

if (OpCodeTable[FoundIdx].Name = 'START') then

begin

IsStartFound := true;

Len := 0;

end else

if (OpCodeTable[FoundIdx].Name = 'END') then

begin

IsEndFound := true;

Len := 0;

end;

end else

Len := OpCodeTable[FoundIdx].Len;

TempTable[i].SymbName := IntToHex(AddrCnt, 2 * BytesPerWORD);

TempTable[i].MOpCode := OpCodeTable[FoundIdx].Code;

TempTable[i].Opd1 := InputTable[i].Opd1;

TempTable[i].Opd2 := InputTable[i].Opd2;

AddrCnt := AddrCnt + Len;

if (IsEndFound) then

break;

end else

begin

Error.ErrType := eINCORRECT_OPCODE;

Error.StrNum := i;

exit;

end;

end;

if (not IsStartFound) then

begin

Error.ErrType := eSTART_MISSING;

Error.StrNum := i;

exit;

end;

if (not IsEndFound) then

begin

Error.ErrType := eEND_MISSING;

Error.StrNum := i;

exit;

end else

begin

ProgLen := AddrCnt - StrToInt('$' + InputTable[0].Opd1);

Header := 'H ' + InputTable[0].SymbName + ' ' + InputTable[0].Opd1 + ' ' + IntToHex(ProgLen, 6);

end;

end;

function GetOpDesc(OpCode: string): TOpCode;

var

i: byte;

begin

Result.Name := '';

for i := 0 to NumOps - 1 do

begin

if (OpCodeTable[i].Code = OpCode) then

begin

Result := OpCodeTable[i];

break;

end;

end;

end;

function IsOpName(Name: string; var OpId: byte): boolean;

var

i: byte;

begin

Result := false;

for i := 0 to NumOps - 1 do

begin

if (Name = OpCodeTable[i].Name) then

begin

Result := true;

OpId := i;

break;

end;

end;

end;

procedure SecondParse(TempTable: array of TComLine; var Output: array of string;

var Error: TError; SymbNameTree: TAVLTree; NumSymbNames: byte; NumComLines: byte);

label

Skip;

var

CurrOpd: string;

OutputOpd: array [0..1] of string;

CurrOpDesc: TOpCode;

i, j, k,

PrevOpdType,

CurrOpdType,

NumQuot,

AddrMethod,

RegId, OpId,

Add: byte;

IsCorrect: boolean;

pSymbNameNode: TPNode;

Value: integer;

begin

for i := 1 to NumComLines - 1 do

begin

Error.StrNum := i;

PrevOpdType := oNONE;

AddrMethod := 0;

CurrOpDesc := GetOpDesc(TempTable[i].MOpCode);

for j := 0 to 1 do

begin

OutputOpd[j] := '';

if (j = 0) then

begin

CurrOpd := TempTable[i].Opd1;

CurrOpdType := CurrOpDesc.Opd1;

end else

begin

CurrOpd := TempTable[i].Opd2;

CurrOpdType := CurrOpDesc.Opd2;

end;

IsCorrect := false;

if (CurrOpdType and oREG <> 0) then

begin

if (IsRegName(CurrOpd, RegId)) then

begin

IsCorrect := true;

if (PrevOpdType = oREG) then

begin

OutputOpd[0][1] := OutputOpd[0][2];

OutputOpd[0][2] := HexAddDec(OutputOpd[j], RegId, 2)[2];

end else

OutputOpd[j] := HexAddDec(OutputOpd[j], RegId, 2);

PrevOpdType := oREG;

goto Skip;

end;

end else

begin

if (IsRegName(CurrOpd, RegId)) then

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end;

if (CurrOpdType and oSYMB_NAME <> 0) and (currOpd <> '') and (CurrOpd[1] = ASM_MARK_SYMBOL) then

begin

pSymbNameNode := SymbNameTree.FindNode(CurrOpd);

if (pSymbNameNode <> nil) then

begin

if (prevOpdType = oSYMB_NAME) then

begin

error.ErrType := eTWO_MEM_OPD;

exit;

end;

OutputOpd[j] := pSymbNameNode^.Inf;

AddrMethod := 1;

IsCorrect := true;

PrevOpdType := oSYMB_NAME;

goto Skip;

end else

begin

Error.ErrType := eSYMB_NAME_NOT_FOUND;

exit;

end;

end else

begin

pSymbNameNode := SymbNameTree.FindNode(CurrOpd);

if (pSymbNameNode <> nil) then

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end;

if (currOpd <> '') and (CurrOpdType and (oVALUE or oEX_VALUE) <> 0) then

begin

IsOpName('BYTE', OpId);

if (TempTable[i].MOpCode = IntToHex(OpId + 1, 2)) then

begin

if ((TryStrToInt('$' + CurrOpd, Value)) and (Value >= 0) and (Value <= MaxByteVal)) then

begin

OutputOpd[j] := IntToHex(Value, 2 * BytesPerBYTE);

IsCorrect := true;

goto Skip;

end else

begin

Error.ErrType := eINCORRECT_OPD;

exit;

if ((Value <> 0) and (CurrOpd[1] <> 'c')) then // ???

goto Skip;

end;

end else

begin

IsOpName('WORD', OpId);

if (TempTable[i].MOpCode = IntToHex(OpId + 1, 2)) then

begin

if ((TryStrToInt('$' + CurrOpd, Value)) and (Value >= 0) and (Value <= MaxWordVal)) then

begin

OutputOpd[j] := IntToHex(Value, 2 * BytesPerWORD);

IsCorrect := true;

goto Skip;

end else

begin

Error.ErrType := eINCORRECT_OPD;

exit;

if (Value <> 0) then

goto Skip;

end;

end else

begin

IsOpName('RESB', OpId);

if (TempTable[i].MOpCode = IntToHex(OpId + 1, 2)) then

begin

if ((TryStrToInt('$' + CurrOpd, Value)) and (Value > 0) and (Value <= MaxResBVal)) then

begin

OutputOpd[j] := IntToHex(0, Value * 2 * BytesPerBYTE);

IsCorrect := true;

goto Skip;

end else

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end else

begin

IsOpName('RESW', OpId);

if (TempTable[i].MOpCode = IntToHex(OpId + 1, 2)) then

begin

if ((TryStrToInt('$' + CurrOpd, Value)) and (Value > 0) and (Value <= MaxResWVal)) then

begin

OutputOpd[j] := IntToHex(0, Value * 2 * BytesPerWORD);

IsCorrect := true;

goto Skip;

end else

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end else

begin

if ((TryStrToInt('$' + CurrOpd, Value)) and (Value <= MaxWordVal)) then

begin

OutputOpd[j] := CurrOpd;

IsCorrect := true;

goto Skip;

end else

begin

if (CurrOpdType and oEX_VALUE = 0) then

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end;

end;

end;

end;

end;

end else

begin

if (TryStrToInt(CurrOpd, Value)) then

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end;

if (CurrOpdType and oEX_VALUE <> 0) then

begin

if (CurrOpd = '?') then

begin

if (TempTable[i].MOpCode = '09') then // BYTE dir.

OutputOpd[j] := IntToHex(0, 2 * BytesPerBYTE)

else

if (TempTable[i].MOpCode = '0A') then // WORD dir.

OutputOpd[j] := IntToHex(0, 2 * BytesPerWORD)

else

OutputOpd[j] := IntToHex(0, 2 * BytesPerWord);

IsCorrect := true;

goto Skip;

end else

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end else

begin

if (CurrOpd = '?') then

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end;

if (CurrOpdType and oSTRING <> 0) then

begin

NumQuot := 0;

for k := 2 to Length(CurrOpd) do

begin

if (CurrOpd[k] = '"') then

inc(NumQuot);

end;

if ((NumQuot = 2) and (CurrOpd[2] = '"') and (CurrOpd[Length(CurrOpd)] = '"')) then

begin

for k := 3 to Length(CurrOpd) - 1 do

begin

OutputOpd[j] := OutputOpd[j] + IntToHex(ord(CurrOpd[k]), 2);

if (k < Length(CurrOpd) - 1) then

OutputOpd[j] := OutputOpd[j];

end;

IsCorrect := true;

end else

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end;

if (CurrOpdType and oNONE <> 0) then

begin

if (CurrOpd = '') then

IsCorrect := true

else begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end;

Skip:

if (not IsCorrect) then

begin

Error.ErrType := eINCORRECT_OPD;

exit;

end;

end;

Output[i] := 'T ' + TempTable[i].SymbName + ' '; // Address

if (not GetOpDesc(TempTable[i].MOpCode).IsDir) then

Add := 2

else

Add := 0;

Output[i] := Output[i] + IntToHex(Length(OutputOpd[0]) + Length(OutputOpd[1]) + Add, 2) + ' '; // Num. symbs.

if (not GetOpDesc(TempTable[i].MOpCode).IsDir) then

Output[i] := Output[i] + HexAddDec(HexMulDec(TempTable[i].MOpCode, 4, 2), AddrMethod, 2) + ' '; // Opcode

Output[i] := Output[i] + OutputOpd[0]; // Operand 1

if (OutputOpd[1] <> '') then

Output[i] := Output[i] + ' ' + OutputOpd[1]; // Operand 2

end;

Output[NumComLines - 1] := 'E ' + TempTable[0].Opd1;

end;

end.