
- •Постановка задачи.
- •Теоретический раздел. Основные понятия.
- •Некоторые возможности Макроязыка
- •Структуры данных Макропроцессора
- •Основные алгоритмы программы.
- •Руководство пользователя.
- •Описание макроязыка.
- •Описание разработанных модулей.
- •Описание разработанных тестов.
- •Список использованной литературы.
- •Листинг программы. Модуль mp.
- •Модуль Assembler.
- •Модуль Main.
- •Модуль MacroGen.
- •Модуль Expr.
- •Модуль Strings.
Модуль 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.