Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add DEF directive #30

Closed
wants to merge 1 commit into from

2 participants

@rx80

Allows: DEF NAME VALUE
Currently only for literal/numeric values
In other ways it works similar to the C #define
It is parsed before any symbols, and only allows for
forward definitions. DEF regName VALUE is not allowed.

@rx80 rx80 Add DEF directive
Allows: DEF NAME VALUE
Currently only for literal/numeric values
In other ways it works similar to the C #define
It is parsed before any symbols, and only allows for
forward definitions. DEF regName VALUE is not allowed.
987eeed
@badsector
Owner

I don't think a separate set for definitions is needed. You can use the existing code for symbols, just instead of an address store the literal value. Symbols are basically constants with their values being set automatically by the assembler to the current size/org when a label is found. All you need to do is replicate the label parsing code with code that stores a symbol with the name from DEF <name> <value> as the symbol/label's name and the value as the symbol's address/value. This way when the symbol is referenced somewhere before its definition, fixups will be added and applied when the symbol is defined. Also less code :-)

@rx80

The problem with this is for symbols with small values (0x0-0x1f) the current fixup code always needs an extra byte.
So if someone tries to use
DEF TRUE 1
or some similar naming of literals, each use will add one extra byte and one extra cycle if we use the symbol+fixup code.
Also, this patch, with a few modifications would allow for "local" defines, like some other assemblers have.

@badsector
Owner

Yeah, this is something that will be fixed in an assembler rewrite (i already have the task in the issue manager btw) that separates the emission of opcodes from scanning. These are two different issues so, i recommend to just use the existing symbols code.

Local symbols are also another issue separate from that. Local labels, variables, defines, etc can be solved in the same manner without special code for each case if a single symbol system is used.

@rx80

ok :) thanks for the reply.

@rx80 rx80 closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Apr 17, 2012
  1. @rx80

    Add DEF directive

    rx80 authored
    Allows: DEF NAME VALUE
    Currently only for literal/numeric values
    In other ways it works similar to the C #define
    It is parsed before any symbols, and only allows for
    forward definitions. DEF regName VALUE is not allowed.
This page is out of date. Refresh to see the latest.
Showing with 121 additions and 5 deletions.
  1. +121 −5 dcpu16.pas
View
126 dcpu16.pas
@@ -70,6 +70,11 @@ TNameAddr = record
ForData: Boolean;
end;
+ TNameValue = record
+ Name: string;
+ Value: TMemoryAddress;
+ end;
+
{ TAssembler }
TAssembler = class
@@ -82,14 +87,15 @@ TAssembler = class
FErrorMessage: string;
FErrorPos: Integer;
FSymbols: array of TNameAddr;
+ FDefines: array of TNameValue;
Fixups: array of TNameAddr;
TokenHead: Integer;
DataSymbol: Boolean;
procedure AddSymbol(AName: string; CodePos: Integer; Addr: TMemoryAddress);
+ procedure AddDefine(AName: string; AValue: TMemoryAddress);
procedure AddFixup(AName: string; CodePos: Integer; Addr: TMemoryAddress);
procedure AddWord(W: Word);
procedure SetORG(L: TMemoryAddress);
- procedure AssembleORG;
function GetOpCodes(AIndex: TMemoryAddress): Word; inline;
function GetSize: TMemoryAddress; inline;
function GetSymbolCount: Integer; inline;
@@ -103,6 +109,11 @@ TAssembler = class
procedure AssembleData;
procedure AssembleReserve;
procedure AssembleInstruction;
+ procedure AssembleORG;
+ procedure ParseDefine;
+ function isDefinedNext: Boolean; inline;
+ function isDefined(AName: string): Boolean; inline;
+ function getDefined(AName: string): TMemoryAddress; inline;
public
procedure Assemble(ACode: string);
property OpCodes[AIndex: TMemoryAddress]: Word read GetOpCodes write SetOpCodes; default;
@@ -151,6 +162,54 @@ procedure TAssembler.AddSymbol(AName: string; CodePos: Integer; Addr: TMemoryAdd
end;
end;
+procedure TAssembler.AddDefine(AName: string; AValue: TMemoryAddress);
+var
+ I: Integer;
+begin
+ if isDefined(AName) then begin
+ SetError('Redefinitions are not allowed', Head);
+ Exit;
+ end;
+
+ SetLength(FDefines, Length(FDefines) + 1);
+ FDefines[High(FDefines)].Name:=AName;
+ FDefines[High(FDefines)].Value:=AValue;
+end;
+
+function TAssembler.isDefined(AName: string): Boolean;
+var
+ I: Integer;
+begin
+ Result := False;
+ for I := 0 to High(FDefines) do
+ if FDefines[I].Name = AName then begin
+ Result := True;
+ break;
+ end;
+end;
+
+function TAssembler.isDefinedNext: Boolean;
+var
+ Token: string;
+ I: Integer;
+begin
+ I := Head;
+ Token := NextToken;
+ Head := I;
+ Result := (Token<>'') and isDefined(Token);
+end;
+
+function TAssembler.getDefined(AName: string): TMemoryAddress;
+var
+ I: Integer;
+begin
+ for I := 0 to High(FDefines) do
+ if FDefines[I].Name = AName then begin
+ Result := FDefines[I].Value;
+ break;
+ end;
+end;
+
procedure TAssembler.AddFixup(AName: string; CodePos: Integer; Addr: TMemoryAddress);
begin
SetLength(Fixups, Length(Fixups) + 1);
@@ -330,6 +389,11 @@ procedure TAssembler.AssembleData;
Exit;
end;
Found:=False;
+ if isDefined(Token) then begin
+ AddWord(getDefined(Token));
+ Found:=True;
+ Break;
+ end;
for I:=0 to High(FSymbols) do
if Symbols[I].Name=Token then begin
AddWord(FSymbols[I].Address);
@@ -376,11 +440,49 @@ procedure TAssembler.AssembleORG;
SetError('Unexpected end of code in ORG', Head);
Exit;
end;
+ if (Code[Head] in ['0'..'9', '$', '-']) then begin
+ I := NextNumber;
+ end else if isDefinedNext then begin
+ I := getDefined(NextToken);
+ end else begin
+ SetError('Number or DEF symbol expected in ORG', Head);
+ Exit;
+ end;
+ CurrentORG := I;
+end;
+
+procedure TAssembler.ParseDefine;
+var
+ I: Integer;
+ Token: string;
+ Reg: TCPURegister;
+begin
+ SkipSpaces;
+ if Head > Len then begin
+ SetError('Unexpected end of code in DEF', Head);
+ Exit;
+ end;
+ if (Code[Head] in ['0'..'9', '$', '-']) then begin
+ SetError('Name expected in DEF', Head);
+ Exit;
+ end;
+ Token:=NextToken;
+ for Reg:=crA to crO do
+ if CPURegisterNames[Reg]=Token then begin
+ SetError('Cannot use a register in DEF', TokenHead);
+ Exit;
+ end;
+ SkipSpaces;
+ if Head > Len then begin
+ SetError('Unexpected end of code in DEF', Head);
+ Exit;
+ end;
if not (Code[Head] in ['0'..'9', '$', '-']) then begin
- SetError('Number expected in ORG', Head);
+ SetError('Value expected in DEF', Head);
Exit;
end;
- CurrentORG:=NextNumber;
+ I := NextNumber and $FFFF;
+ AddDefine(Token, I);
end;
procedure TAssembler.AssembleInstruction;
@@ -422,8 +524,12 @@ procedure TAssembler.AssembleInstruction;
SetError('Unexpected end of code inside memory access parameter for ' + CPUInstructionNames[AInstr], Head);
Exit(0);
end;
- if Code[Head] in ['0'..'9', '$'] then begin
- I:=NextNumber and $FFFF;
+ if (Code[Head] in ['0'..'9', '$']) or isDefinedNext then begin
+ if isDefinedNext then begin
+ I := getDefined(NextToken);
+ end else begin
+ I := NextNumber and $FFFF;
+ end;
SkipSpaces;
if Head > Len then begin
SetError('Unexpected end of code inside memory access parameter for ' + CPUInstructionNames[AInstr] + ' after address', Head);
@@ -471,6 +577,10 @@ procedure TAssembler.AssembleInstruction;
Inc(Head);
Exit($08 + Ord(Reg));
end;
+ if isDefined(Token) then begin
+ AddWord(getDefined(Token));
+ goto fuckit;
+ end;
for I:=SymbolCount - 1 downto 0 do
if FSymbols[I].Name=Token then begin
AddWord(FSymbols[I].Address);
@@ -525,6 +635,8 @@ procedure TAssembler.AssembleInstruction;
for Reg:=crA to crJ do
if CPURegisterNames[Reg]=Token then
Exit(Ord(Reg));
+ if isDefined(Token) then
+ Exit(WriteLiteral(getDefined(Token)));
for I:=SymbolCount - 1 downto 0 do
if FSymbols[I].Name=Token then
Exit(WriteLiteral(FSymbols[I].Address));
@@ -577,6 +689,10 @@ procedure TAssembler.AssembleInstruction;
AssembleORG;
Exit;
end;
+ if (InstrName='DEF') then begin
+ ParseDefine;
+ Exit;
+ end;
for Instr:=Low(TCPUInstruction) to High(TCPUInstruction) do begin
if CPUInstructionNames[Instr]=InstrName then begin
DataSymbol:=False;
Something went wrong with that request. Please try again.