Add checking that labels and references are alphabumeric to the assembler and a warn about its lack of checking for references to non-existing labels in the readme, and add memory overflow errors
This commit is contained in:
parent
49942ac88d
commit
e2b545afa5
|
@ -20,6 +20,13 @@ var
|
|||
Bin: array [0 .. $ffef] of byte; //Assembled binary
|
||||
Prog: file of byte; //Program file
|
||||
|
||||
//Check if a string is alphanumeric
|
||||
function IsAlphaNum (Arg: string): boolean;
|
||||
begin
|
||||
for Count := 1 to length (Arg) do if not (Arg [Count] in ['a' .. 'z', 'A' .. 'Z', '0' .. '9']) then exit (false);
|
||||
exit (true);
|
||||
end;
|
||||
|
||||
//Print an argument error and abort
|
||||
procedure ArgError;
|
||||
begin
|
||||
|
@ -31,7 +38,7 @@ end;
|
|||
procedure MemError;
|
||||
begin
|
||||
if (BP + 2) >= $fff0 then begin
|
||||
writeln ('Error (line ', LP, '): out of memory');
|
||||
writeln ('Error (line ', LP, '): memory overflow');
|
||||
halt;
|
||||
end;
|
||||
end;
|
||||
|
@ -78,6 +85,12 @@ begin
|
|||
//Read a line
|
||||
readln (Line);
|
||||
|
||||
//A hack for fixing an unexplained extra readln after the loop that does nothing
|
||||
if BP = $fff0 then begin
|
||||
writeln ('Error (line ', LP, '): memory overflow');
|
||||
halt;
|
||||
end;
|
||||
|
||||
//Remove the comment if any
|
||||
Line := Trim (ExtractDelimited (1, Line, [';']));
|
||||
|
||||
|
@ -93,27 +106,40 @@ begin
|
|||
|
||||
//Check if the first element is a label
|
||||
if RightStr (Trim (ExtractWord (1, Line, [' ', ' '])), 1) = ':' then begin
|
||||
//Find the first empty slot in the label table
|
||||
Count := 0;
|
||||
while Lbl [Count] .Lbl <> '' do Count := Count + 1;
|
||||
//Extract the label
|
||||
Lbl [Count] .Addr := BP;
|
||||
Elem [0] := Trim (ExtractDelimited (1, Line, [':']));
|
||||
Lbl [Count] .Lbl := Elem [0];
|
||||
Line := Trim (ExtractDelimited (2, Line, [':']));
|
||||
//Check for forward references
|
||||
Count := 0;
|
||||
repeat
|
||||
while CompareText (Elem [0], Ref [Count] .Lbl) <> 0 do begin
|
||||
if Ref [Count] .Lbl = '' then break;
|
||||
Count := Count + 1;
|
||||
//Check if the label is hexadecimal
|
||||
try
|
||||
Count := Hex2Dec (Elem [0]);
|
||||
writeln ('Error (line ', LP, '): labels cannot be hexadecimal numbers');
|
||||
halt;
|
||||
except
|
||||
//Check if the label is alphanumeric
|
||||
if IsAlphaNum (Elem [0]) = false then begin
|
||||
writeln ('Error (line ', LP, '): labels must be alphanumeric');
|
||||
halt;
|
||||
end;
|
||||
if Ref [Count] .Lbl <> '' then begin
|
||||
Bin [Ref [Count] .Addr] := BP shr 8;
|
||||
Bin [Ref [Count] .Addr + 1] := BP and $00ff;
|
||||
Count := Count + 1;
|
||||
end;
|
||||
until Ref [Count] .Lbl = '';
|
||||
//Find the first empty slot in the label table
|
||||
Count := 0;
|
||||
while Lbl [Count] .Lbl <> '' do Count := Count + 1;
|
||||
//Store the label in the table
|
||||
Lbl [Count] .Addr := BP;
|
||||
Lbl [Count] .Lbl := Elem [0];
|
||||
//Check for forward references
|
||||
Count := 0;
|
||||
repeat
|
||||
while CompareText (Elem [0], Ref [Count] .Lbl) <> 0 do begin
|
||||
if Ref [Count] .Lbl = '' then break;
|
||||
Count := Count + 1;
|
||||
end;
|
||||
if Ref [Count] .Lbl <> '' then begin
|
||||
Bin [Ref [Count] .Addr] := BP shr 8;
|
||||
Bin [Ref [Count] .Addr + 1] := BP and $00ff;
|
||||
Count := Count + 1;
|
||||
end;
|
||||
until Ref [Count] .Lbl = '';
|
||||
end;
|
||||
end;
|
||||
|
||||
//Check for the org pseudo-instruction
|
||||
|
@ -222,6 +248,11 @@ begin
|
|||
else ArgError;
|
||||
except
|
||||
//Label reference
|
||||
//Check if the reference is alphanumeric
|
||||
if IsAlphaNum (Elem [3]) = false then begin
|
||||
writeln ('Error (line ', LP, '): references must be alphanumeric');
|
||||
halt;
|
||||
end;
|
||||
//Backwards
|
||||
Count := 0;
|
||||
while CompareText (Elem [3], Lbl [Count] .Lbl) <> 0 do begin
|
||||
|
@ -234,7 +265,7 @@ begin
|
|||
//Find the first empty slot in the reference table
|
||||
Count := 0;
|
||||
while Ref [Count] .Lbl <> '' do Count := Count + 1;
|
||||
//Extract the reference
|
||||
//Store the reference in the table
|
||||
Ref [Count] .Addr := BP + 1;
|
||||
Ref [Count] .Lbl := Elem [3];
|
||||
//Placeholder
|
||||
|
@ -254,6 +285,11 @@ begin
|
|||
else ArgError;
|
||||
except
|
||||
//Label reference
|
||||
//Check if the reference is alphanumeric
|
||||
if IsAlphaNum (Elem [2]) = false then begin
|
||||
writeln ('Error (line ', LP, '): references must be alphanumeric');
|
||||
halt;
|
||||
end;
|
||||
//Backwards
|
||||
Count := 0;
|
||||
while CompareText (Elem [2], Lbl [Count] .Lbl) <> 0 do begin
|
||||
|
@ -266,7 +302,7 @@ begin
|
|||
//Find the first empty slot in the reference table
|
||||
Count := 0;
|
||||
while Ref [Count] .Lbl <> '' do Count := Count + 1;
|
||||
//Extract the reference
|
||||
//Store the reference in the table
|
||||
Ref [Count] .Addr := BP + 1;
|
||||
Ref [Count] .Lbl := Elem [2];
|
||||
//Placeholder
|
||||
|
@ -294,6 +330,11 @@ begin
|
|||
else ArgError;
|
||||
except
|
||||
//Label reference
|
||||
//Check if the reference is alphanumeric
|
||||
if IsAlphaNum (Elem [4]) = false then begin
|
||||
writeln ('Error (line ', LP, '): references must be alphanumeric');
|
||||
halt;
|
||||
end;
|
||||
//Backwards
|
||||
Count := 0;
|
||||
while CompareText (Elem [4], Lbl [Count] .Lbl) <> 0 do begin
|
||||
|
@ -306,7 +347,7 @@ begin
|
|||
//Find the first empty slot in the reference table
|
||||
Count := 0;
|
||||
while Ref [Count] .Lbl <> '' do Count := Count + 1;
|
||||
//Extract the reference
|
||||
//Store the reference in the table
|
||||
Ref [Count] .Addr := BP + 1;
|
||||
Ref [Count] .Lbl := Elem [4];
|
||||
//Placeholder
|
||||
|
@ -329,9 +370,6 @@ begin
|
|||
//Increment the line pointer
|
||||
LP := LP + 1;
|
||||
|
||||
//A hack for fixing an unexplained extra readln after the loop that does nothing
|
||||
if BP = $fff0 then break;
|
||||
|
||||
until eof ();
|
||||
|
||||
//Set the end pointer and reset the byte pointer to the start of the program
|
||||
|
|
|
@ -50,7 +50,10 @@ begin
|
|||
read (Prog, Bin [BP]);
|
||||
BP := BP + 1;
|
||||
until (eof (Prog)) or (BP = $fff0);
|
||||
|
||||
if BP = $fff0 then begin
|
||||
writeln ('Error: memory overflow');
|
||||
halt;
|
||||
end;
|
||||
//Save the end point and reinitialise the byte pointer
|
||||
EP := BP;
|
||||
BP := 0;
|
||||
|
|
|
@ -39,6 +39,10 @@ begin
|
|||
read (Prog, Mem [IP]);
|
||||
IP := IP + 1;
|
||||
until (eof (Prog)) or (IP = $fff0);
|
||||
if IP = $fff0 then begin
|
||||
writeln ('Error: memory overflow');
|
||||
halt;
|
||||
end;
|
||||
|
||||
//Reinitialise the instruction pointer
|
||||
IP := 0;
|
||||
|
|
|
@ -67,6 +67,9 @@ ORG defines the starting address of the program: it can only occur as
|
|||
the first instruction and cannot have a label, and is not required if
|
||||
the starting address is 0. DATA introduces a byte of data.
|
||||
|
||||
Note that the assembler does not check for references to non-existing
|
||||
labels.
|
||||
|
||||
Memory-Mapped Devices
|
||||
---------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue