source: branches/bigint/Assembler.pas

Last change on this file was 8, checked in by chronos, 3 months ago
  • Added: Common package.
  • Added: Memory form to show content of memory.
File size: 8.1 KB
Line 
1unit Assembler;
2
3interface
4
5uses
6 Classes, SysUtils, Instructions, Cpu, Generics.Collections,
7 IntMemory, Message, Parser, Int;
8
9type
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;
18
19 { TAssembler }
20
21 TAssembler = class
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: TIntMemory;
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;
43 constructor Create;
44 destructor Destroy; override;
45 property OnError: TErrorEvent read FOnError write FOnError;
46 end;
47
48
49implementation
50
51{ TLabelRef }
52
53class function TLabelRef.Create(LabelName: string; RefPos: Integer): TLabelRef;
54begin
55 Result.LabelName := LabelName;
56 Result.RefPos := RefPos;
57end;
58
59{ TAssembler }
60
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] = ptIndirect2 then begin
216 Parser.Expect(tkSpecialSymbol, '((');
217 Parser.Expect(tkSpecialSymbol, '(');
218 Token := Parser.ReadNext;
219 if TryStrToInt(Token.Value, Number) then
220 Memory.WritePos(Number)
221 else Error('Expected numeric index error', Token.Pos);
222 Parser.Expect(tkSpecialSymbol, '))');
223 Parser.Expect(tkSpecialSymbol, '))');
224 end else
225 if InstructionInfo.Params[I] = ptIndirect then begin
226 Parser.Expect(tkSpecialSymbol, '(');
227 Token := Parser.ReadNext;
228 if TryStrToInt(Token.Value, Number) then
229 Memory.WritePos(Number)
230 else Error('Expected numeric index error', Token.Pos);
231 Parser.Expect(tkSpecialSymbol, ')');
232 end else raise Exception.Create('Unsupported parameter type');
233 end;
234 end;
235 if not Result then Parser.Pos := LastPos;
236end;
237
238function TAssembler.ParseLabel: Boolean;
239var
240 LastPos: TParserPos;
241 Token: TToken;
242 Addr: TInt;
243begin
244 Result := False;
245 LastPos := Parser.Pos;
246 Token := Parser.ReadNext;
247 if Parser.CheckNextAndRead(tkSpecialSymbol, ':') then begin
248 Result := True;
249 if not Labels.TryGetValue(Token.Value, Addr) then begin
250 Labels.Add(Token.Value, Memory.Position);
251 end else Error('Duplicate label ' + Token.Value + '.', Token.Pos);
252 end;
253 if not Result then Parser.Pos := LastPos;
254end;
255
256procedure TAssembler.LoadFromFile(FileName: string);
257var
258 Lines: TStringList;
259begin
260 Lines := TStringList.Create;
261 try
262 Lines.LoadFromFile(FileName);
263 Compile(Lines.Text);
264 finally
265 Lines.Free;
266 end;
267end;
268
269function TAssembler.ParseStr(var Text: string; Separator: string): string;
270var
271 P: Integer;
272begin
273 P := Pos(Separator, Text);
274 if P > 0 then begin
275 Result := Trim(Copy(Text, 1, P - 1));
276 Text := Trim(Copy(Text, P + 1, MaxInt));
277 end else begin
278 Result := Trim(Text);
279 Text := '';
280 end;
281end;
282
283constructor TAssembler.Create;
284begin
285 Parser := TParser.Create;
286 Parser.OnError := Error;
287 Message := TMessages.Create;
288 Memory := TIntMemory.Create;
289 InstructionSet := TInstructionSet.Create;
290 Labels := TDictionary<string, TInt>.Create;
291 LabelRefs := TList<TLabelRef>.Create;
292 Variables := TDictionary<string, TInt>.Create;
293end;
294
295destructor TAssembler.Destroy;
296begin
297 FreeAndNil(Variables);
298 FreeAndNil(Labels);
299 FreeAndNil(LabelRefs);
300 FreeAndNil(InstructionSet);
301 FreeAndNil(Memory);
302 FreeAndNil(Message);
303 FreeAndNil(Parser);
304 inherited;
305end;
306
307end.
308
Note: See TracBrowser for help on using the repository browser.