Changeset 4


Ignore:
Timestamp:
Aug 1, 2024, 10:47:04 PM (3 months ago)
Author:
chronos
Message:
  • Added: Assembler to parse instructions from text string and produce binary code.
Location:
branches/bigint
Files:
4 added
5 edited

Legend:

Unmodified
Added
Removed
  • branches/bigint/Assembler.pas

    r2 r4  
    44
    55uses
    6   Classes, SysUtils;
     6  Classes, SysUtils, Instructions, Cpu, Generics.Collections,
     7  Memory, Message, Parser, Int;
    78
    89type
     10  { TLabelRef }
     11
     12  TLabelRef = record
     13    LabelName: string;
     14    RefPos: Integer;
     15    TextPos: TPoint;
     16    class function Create(LabelName: string; RefPos: Integer): TLabelRef; static;
     17  end;
    918
    1019  { TAssembler }
    1120
    1221  TAssembler = class
    13     Lines: TStringList;
    14     procedure Assemble;
     22  private
     23    FOnError: TErrorEvent;
     24    Parser: TParser;
     25    function ParseVar: Boolean;
     26    function ParseDb: Boolean;
     27    function ParseOrg: Boolean;
     28    function ParseInstruction: Boolean;
     29    function ParseLabel: Boolean;
     30    procedure UpdateLabelRefs;
     31    procedure ParseNumParam(Token: TToken);
     32  public
     33    InstructionSet: TInstructionSet;
     34    Memory: TMemory;
     35    Labels: TDictionary<string, TInt>;
     36    LabelRefs: TList<TLabelRef>;
     37    Variables: TDictionary<string, TInt>;
     38    Message: TMessages;
     39    procedure Error(Text: string; Pos: TPoint);
     40    procedure Compile(Source: string);
     41    procedure LoadFromFile(FileName: string);
     42    function ParseStr(var Text: string; Separator: string): string;
    1543    constructor Create;
    1644    destructor Destroy; override;
     45    property OnError: TErrorEvent read FOnError write FOnError;
    1746  end;
    1847
     
    2049implementation
    2150
     51{ TLabelRef }
     52
     53class function TLabelRef.Create(LabelName: string; RefPos: Integer): TLabelRef;
     54begin
     55  Result.LabelName := LabelName;
     56  Result.RefPos := RefPos;
     57end;
     58
    2259{ TAssembler }
    2360
    24 procedure TAssembler.Assemble;
    25 begin
    26 
     61procedure TAssembler.UpdateLabelRefs;
     62var
     63  I: Integer;
     64  Addr: TInt;
     65begin
     66  for I := 0 to LabelRefs.Count - 1 do begin
     67    if Labels.TryGetValue(LabelRefs[I].LabelName, Addr) then
     68      Memory[LabelRefs[I].RefPos] := Addr
     69      else Error('Label ' + LabelRefs[I].LabelName + ' referenced but not defined.', LabelRefs[I].TextPos);
     70  end;
     71end;
     72
     73procedure TAssembler.ParseNumParam(Token: TToken);
     74var
     75  Addr: TInt;
     76begin
     77  if Token.Kind = tkNumber then begin
     78    if TryStrToInt64(Token.Value, Addr) then begin
     79      Memory.WritePos(Addr);
     80    end;
     81  end else
     82  if Token.Kind = tkIdentifier then begin;
     83    if Variables.TryGetValue(Token.Value, Addr) then begin
     84      Memory.WritePos(Addr);
     85    end else
     86    if Labels.TryGetValue(Token.Value, Addr) then begin
     87      Memory.WritePos(Addr);
     88    end else begin
     89      LabelRefs.Add(TLabelRef.Create(Token.Value, Memory.Position));
     90      Memory.WritePos(0);
     91    end;
     92  end else Error('Unexpected token ' + Token.Value + '.', Token.Pos);
     93end;
     94
     95procedure TAssembler.Error(Text: string; Pos: TPoint);
     96begin
     97  Message.AddMessage(Text, Pos);
     98  if Assigned(FOnError) then
     99    FOnError(Text, Pos);
     100end;
     101
     102procedure TAssembler.Compile(Source: string);
     103begin
     104  Message.Clear;
     105  Memory.Size := 10000;
     106  Labels.Clear;
     107  LabelRefs.Clear;
     108  Parser.Reset;
     109  Parser.Source := Source;
     110  while not Parser.CheckNextKind(tkEof) do begin
     111    ParseLabel;
     112    if ParseVar then begin
     113    end else
     114    if ParseDb then begin
     115    end else
     116    if ParseOrg then begin
     117    end else
     118    if ParseInstruction then begin
     119    end;
     120    if Parser.CheckNextKind(tkEof) then begin
     121    end else Parser.Expect(tkEol);
     122  end;
     123  Parser.Expect(tkEof);
     124  UpdateLabelRefs;
     125  Memory.Size := Memory.Position;
     126  Error('Compilation finished.', Point(0, 0));
     127end;
     128
     129function TAssembler.ParseVar: Boolean;
     130var
     131  TokenName: TToken;
     132  TokenValue: TToken;
     133  Number: TInt;
     134begin
     135  Result := False;
     136  if Parser.CheckNextAndRead(tkIdentifier, 'VAR') then begin
     137    Result := True;
     138    while True do begin
     139      TokenName := Parser.ReadNext;
     140      if TokenName.Kind = tkIdentifier then begin
     141        TokenValue := Parser.ReadNext;
     142        if TokenValue.Kind = tkNumber then begin
     143          if not Labels.ContainsKey(TokenName.Value) and not Variables.ContainsKey(TokenName.Value) then begin
     144            if TryStrToInt64(TokenValue.Value, Number) then
     145              Variables.Add(TokenName.Value, Number)
     146            else Error('Expected number', TokenValue.Pos);
     147          end else Error('Duplicate variable name ' + TokenName.Value, TokenName.Pos);
     148        end else Error('Expected variable value.', TokenValue.Pos);
     149      end else Error('Expected variable name.', TokenName.Pos);
     150      if Parser.CheckNextAndRead(tkSpecialSymbol, ',') then begin
     151        Continue;
     152      end;
     153      Break;
     154    end;
     155  end;
     156end;
     157
     158function TAssembler.ParseDb: Boolean;
     159var
     160  Token: TToken;
     161begin
     162  Result := False;
     163  if Parser.CheckNextAndRead(tkIdentifier, 'DB') then begin
     164    Result := True;
     165    while True do begin
     166      Token := Parser.ReadNext;
     167      if Token.Kind = tkString then begin
     168        Memory.WriteStringPos(Token.Value);
     169      end else
     170        ParseNumParam(Token);
     171      if Parser.CheckNextAndRead(tkSpecialSymbol, ',') then begin
     172        Continue;
     173      end;
     174      Break;
     175    end;
     176  end;
     177end;
     178
     179function TAssembler.ParseOrg: Boolean;
     180var
     181  Token: TToken;
     182begin
     183  Result := False;
     184  if Parser.CheckNextAndRead(tkIdentifier, 'ORG') then begin
     185    Result := True;
     186    Token := Parser.ReadNext;
     187    if Token.Kind = tkNumber then begin
     188      Memory.Position := StrToInt(Token.Value);
     189    end else Error('Expected number but ' + Token.Value + ' found.', Token.Pos);
     190  end;
     191end;
     192
     193function TAssembler.ParseInstruction: Boolean;
     194var
     195  InstructionInfo: TInstructionInfo;
     196  I: Integer;
     197  Token: TToken;
     198  LastPos: TParserPos;
     199  Number: Integer;
     200begin
     201  Result := False;
     202  LastPos := Parser.Pos;
     203  Token := Parser.ReadNext;
     204  InstructionInfo := InstructionSet.SearchName(Token.Value);
     205  if Assigned(InstructionInfo) then begin
     206    Result := True;
     207    Memory.WritePos(TInt(InstructionInfo.Instruction));
     208    for I := 0 to Length(InstructionInfo.Params) - 1 do begin
     209      if I > 0 then
     210        Parser.Expect(tkSpecialSymbol, ',');
     211      if InstructionInfo.Params[I] = ptNumber then begin
     212        Token := Parser.ReadNext;
     213        ParseNumParam(Token);
     214      end else
     215      if InstructionInfo.Params[I] = ptIndirect then begin
     216        Parser.Expect(tkSpecialSymbol, '(');
     217        Token := Parser.ReadNext;
     218        if TryStrToInt(Token.Value, Number) then
     219          Memory.WritePos(Number)
     220          else Error('Expected numeric index error', Token.Pos);
     221        Parser.Expect(tkSpecialSymbol, ')');
     222      end else raise Exception.Create('Unsupported parameter type');
     223    end;
     224  end;
     225  if not Result then Parser.Pos := LastPos;
     226end;
     227
     228function TAssembler.ParseLabel: Boolean;
     229var
     230  LastPos: TParserPos;
     231  Token: TToken;
     232  Addr: TInt;
     233begin
     234  Result := False;
     235  LastPos := Parser.Pos;
     236  Token := Parser.ReadNext;
     237  if Parser.CheckNextAndRead(tkSpecialSymbol, ':') then begin
     238    Result := True;
     239    if not Labels.TryGetValue(Token.Value, Addr) then begin
     240      Labels.Add(Token.Value, Memory.Position);
     241    end else Error('Duplicate label ' + Token.Value + '.', Token.Pos);
     242  end;
     243  if not Result then Parser.Pos := LastPos;
     244end;
     245
     246procedure TAssembler.LoadFromFile(FileName: string);
     247var
     248  Lines: TStringList;
     249begin
     250  Lines := TStringList.Create;
     251  try
     252    Lines.LoadFromFile(FileName);
     253    Compile(Lines.Text);
     254  finally
     255    Lines.Free;
     256  end;
     257end;
     258
     259function TAssembler.ParseStr(var Text: string; Separator: string): string;
     260var
     261  P: Integer;
     262begin
     263  P := Pos(Separator, Text);
     264  if P > 0 then begin
     265    Result := Trim(Copy(Text, 1, P - 1));
     266    Text := Trim(Copy(Text, P + 1, MaxInt));
     267  end else begin
     268    Result := Trim(Text);
     269    Text := '';
     270  end;
    27271end;
    28272
    29273constructor TAssembler.Create;
    30274begin
    31   Lines := TStringList.Create;
     275  Parser := TParser.Create;
     276  Parser.OnError := Error;
     277  Message := TMessages.Create;
     278  Memory := TMemory.Create;
     279  InstructionSet := TInstructionSet.Create;
     280  Labels := TDictionary<string, TInt>.Create;
     281  LabelRefs := TList<TLabelRef>.Create;
     282  Variables := TDictionary<string, TInt>.Create;
    32283end;
    33284
    34285destructor TAssembler.Destroy;
    35286begin
    36   FreeAndNil(Lines);
     287  FreeAndNil(Variables);
     288  FreeAndNil(Labels);
     289  FreeAndNil(LabelRefs);
     290  FreeAndNil(InstructionSet);
     291  FreeAndNil(Memory);
     292  FreeAndNil(Message);
     293  FreeAndNil(Parser);
    37294  inherited;
    38295end;
  • branches/bigint/BigIntVM.lpi

    r2 r4  
    118118        <IsPartOfProject Value="True"/>
    119119      </Unit>
     120      <Unit>
     121        <Filename Value="Instructions.pas"/>
     122        <IsPartOfProject Value="True"/>
     123      </Unit>
     124      <Unit>
     125        <Filename Value="Parser.pas"/>
     126        <IsPartOfProject Value="True"/>
     127      </Unit>
     128      <Unit>
     129        <Filename Value="Message.pas"/>
     130        <IsPartOfProject Value="True"/>
     131      </Unit>
     132      <Unit>
     133        <Filename Value="Example.asm"/>
     134        <IsPartOfProject Value="True"/>
     135      </Unit>
    120136    </Units>
    121137  </ProjectOptions>
  • branches/bigint/BigIntVM.lpr

    r2 r4  
    1010  Interfaces, // this includes the LCL widgetset
    1111  Forms, FormMain, Cpu, Memory, Int, Machine, DeviceManager, Screen, Console,
    12   Device, Assembler
     12  Device, Assembler, Instructions, Parser, Message
    1313  { you can add units after this };
    1414
  • branches/bigint/FormMain.pas

    r3 r4  
    55uses
    66  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Machine, Int,
    7   Cpu;
     7  Cpu, Assembler;
    88
    99type
     
    4545procedure TFormMain.FormShow(Sender: TObject);
    4646var
    47   Label1: TInt;
     47  Assembler: TAssembler;
     48  Lines: TStringList;
    4849begin
    49   with Machine.Memory do begin
    50     WritePos(TInt(inLoadConst));
    51     WritePos(1000);
    52     WritePos(Ord('A'));
     50  Lines := TStringList.Create;
     51  Lines.LoadFromFile('Example.asm');
    5352
    54     WritePos(TInt(inLoadConst));
    55     WritePos(1001);
    56     WritePos(20);
     53  Assembler := TAssembler.Create;
     54  with Assembler do begin
     55    Compile(Lines.Text);
     56    Machine.Memory.CopyFrom(Memory, 0, 0, Memory.Size);
     57    Free;
     58  end;
    5759
    58     Label1 := Position;
     60  Lines.Free;
    5961
    60     WritePos(TInt(inOutput));
    61     WritePos(0);
    62     WritePos(1000);
    63 
    64     WritePos(TInt(inInc));
    65     WritePos(1000);
    66 
    67     WritePos(TInt(inDec));
    68     WritePos(1001);
    69 
    70     WritePos(TInt(inJumpNotZero));
    71     WritePos(1001);
    72     WritePos(Label1);
    73 
    74     WritePos(TInt(inHalt));
    75   end;
    7662  Machine.Run;
    7763end;
  • branches/bigint/Memory.pas

    r3 r4  
    2121    procedure WritePos(Data: TInt);
    2222    function ReadPos: TInt;
     23    procedure CopyFrom(Source: TMemory; Dst, Src, Count: TInt);
     24    procedure WriteStringPos(Value: string);
    2325    property Size: TInt read GetSize write SetSize;
    2426    property Position: TInt read FPosition write FPosition;
     27    property Items[Index: TInt]: TInt read Read write Write; default;
    2528  end;
    2629
     
    6265end;
    6366
     67procedure TMemory.CopyFrom(Source: TMemory; Dst, Src, Count: TInt);
     68var
     69  I: Integer;
     70begin
     71  for I := 0 to Count - 1 do begin
     72    Write(Dst, Source.Read(Src));
     73    Inc(Dst);
     74    Inc(Src);
     75  end;
     76end;
     77
     78procedure TMemory.WriteStringPos(Value: string);
     79var
     80  I: Integer;
     81begin
     82  if Length(Value) > 0 then begin
     83    if Position + Length(Value) > Size then Size := Position + Length(Value);
     84    for I := 0 to Length(Value) - 1 do
     85      Items[Position + I] := Ord(Value[I + 1]);
     86    Inc(FPosition, Length(Value));
     87  end;
     88end;
     89
    6490end.
    6591
Note: See TracChangeset for help on using the changeset viewer.