source: branches/CpuSingleSize/Assembler.pas

Last change on this file was 238, checked in by chronos, 16 months ago
  • Modified: Removed U prefix from unit names.
  • Fixed: Memory leaks.
File size: 10.0 KB
Line 
1unit Assembler;
2
3interface
4
5uses
6 Classes, SysUtils, Instructions, Cpu, Generics.Collections,
7 Memory, Message, Parser;
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: TMemory;
35 Labels: TDictionary<string, Integer>;
36 LabelRefs: TList<TLabelRef>;
37 Variables: TDictionary<string, Integer>;
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: Integer;
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: TInteger;
76begin
77 if Token.Kind = tkNumber then begin
78 if TryStrToInt(Token.Value, Addr) then begin
79 Memory.Write(Addr);
80 end;
81 end else
82 if Token.Kind = tkIdentifier then begin;
83 if Variables.TryGetValue(Token.Value, Addr) then begin
84 Memory.Write(Addr);
85 end else
86 if Labels.TryGetValue(Token.Value, Addr) then begin
87 Memory.Write(Addr);
88 end else begin
89 LabelRefs.Add(TLabelRef.Create(Token.Value, Memory.Position));
90 Memory.Write(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 := 0;
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 Error('Compilation finished.', Point(0, 0));
126end;
127
128function TAssembler.ParseVar: Boolean;
129var
130 TokenName: TToken;
131 TokenValue: TToken;
132 Number: TInteger;
133begin
134 Result := False;
135 if Parser.CheckNextAndRead(tkIdentifier, 'VAR') then begin
136 Result := True;
137 while True do begin
138 TokenName := Parser.ReadNext;
139 if TokenName.Kind = tkIdentifier then begin
140 TokenValue := Parser.ReadNext;
141 if TokenValue.Kind = tkNumber then begin
142 if not Labels.ContainsKey(TokenName.Value) and not Variables.ContainsKey(TokenName.Value) then begin
143 if TryStrToInt(TokenValue.Value, Number) then
144 Variables.Add(TokenName.Value, Number)
145 else Error('Expected number', TokenValue.Pos);
146 end else Error('Duplicate variable name ' + TokenName.Value, TokenName.Pos);
147 end else Error('Expected variable value.', TokenValue.Pos);
148 end else Error('Expected variable name.', TokenName.Pos);
149 if Parser.CheckNextAndRead(tkSpecialSymbol, ',') then begin
150 Continue;
151 end;
152 Break;
153 end;
154 end;
155end;
156
157function TAssembler.ParseDb: Boolean;
158var
159 Token: TToken;
160begin
161 Result := False;
162 if Parser.CheckNextAndRead(tkIdentifier, 'DB') then begin
163 Result := True;
164 while True do begin
165 Token := Parser.ReadNext;
166 if Token.Kind = tkString then begin
167 Memory.WriteString(Token.Value);
168 end else
169 ParseNumParam(Token);
170 if Parser.CheckNextAndRead(tkSpecialSymbol, ',') then begin
171 Continue;
172 end;
173 Break;
174 end;
175 end;
176end;
177
178function TAssembler.ParseOrg: Boolean;
179var
180 Token: TToken;
181begin
182 Result := False;
183 if Parser.CheckNextAndRead(tkIdentifier, 'ORG') then begin
184 Result := True;
185 Token := Parser.ReadNext;
186 if Token.Kind = tkNumber then begin
187 Memory.Position := StrToInt(Token.Value);
188 end else Error('Expected number but ' + Token.Value + ' found.', Token.Pos);
189 end;
190end;
191
192function TAssembler.ParseInstruction: Boolean;
193var
194 InstructionInfo: TInstructionInfo;
195 I: Integer;
196 Token: TToken;
197 LastPos: TParserPos;
198 Number: Integer;
199begin
200 Result := False;
201 LastPos := Parser.Pos;
202 Token := Parser.ReadNext;
203 InstructionInfo := InstructionSet.SearchName(Token.Value);
204 if Assigned(InstructionInfo) then begin
205 Result := True;
206 Memory.Write(Integer(InstructionInfo.Instruction));
207 for I := 0 to Length(InstructionInfo.Params) - 1 do begin
208 if I > 0 then
209 Parser.Expect(tkSpecialSymbol, ',');
210 if InstructionInfo.Params[I] = ptNumber then begin
211 Token := Parser.ReadNext;
212 ParseNumParam(Token);
213 end else
214 if InstructionInfo.Params[I] = ptReg then begin
215 Token := Parser.ReadNext;
216 if (Token.Value <> '') and (Token.Value[1] = 'R') then begin
217 Token.Value := Copy(Token.Value, 2, MaxInt);
218 if TryStrToInt(Token.Value, Number) then
219 Memory.Write(Number)
220 else Error('Expected numeric register index error', Token.Pos);
221 end else Error('Expected register name starting with R character.', Token.Pos);
222 end else
223 if InstructionInfo.Params[I] = ptRegIndirect then begin
224 Parser.Expect(tkSpecialSymbol, '(');
225 Token := Parser.ReadNext;
226 if (Token.Value <> '') and (Token.Value[1] = 'R') then begin
227 Token.Value := Copy(Token.Value, 2, MaxInt);
228 if TryStrToInt(Token.Value, Number) then
229 Memory.Write(Number)
230 else Error('Expected numeric register index error', Token.Pos);
231 end else Error('Expected register name starting with R character.', Token.Pos);
232 Parser.Expect(tkSpecialSymbol, ')');
233 end else
234 if InstructionInfo.Params[I] = ptRegIndirectIndex then begin
235 Parser.Expect(tkSpecialSymbol, '(');
236 Token := Parser.ReadNext;
237 if (Token.Value <> '') and (Token.Value[1] = 'R') then begin
238 Token.Value := Copy(Token.Value, 2, MaxInt);
239 if TryStrToInt(Token.Value, Number) then begin
240 Memory.Write(Number);
241 Parser.Expect(tkSpecialSymbol, '+');
242 Token := Parser.ReadNext;
243 ParseNumParam(Token);
244 end else Error('Expected numeric register index error', Token.Pos);
245 end else Error('Expected register name starting with R character.', Token.Pos);
246 Parser.Expect(tkSpecialSymbol, ')');
247 end else
248 if InstructionInfo.Params[I] = ptRegIndirectGroup then begin
249 Parser.Expect(tkSpecialSymbol, '(');
250 Token := Parser.ReadNext;
251 if (Token.Value <> '') and (Token.Value[1] = 'R') then begin
252 Token.Value := Copy(Token.Value, 2, MaxInt);
253 if TryStrToInt(Token.Value, Number) then begin
254 Memory.Write(Number);
255 Parser.Expect(tkSpecialSymbol, ':');
256 Token := Parser.ReadNext;
257 if (Token.Value <> '') and (Token.Value[1] = 'R') then begin
258 Token.Value := Copy(Token.Value, 2, MaxInt);
259 if TryStrToInt(Token.Value, Number) then begin
260 Memory.Write(Number);
261 end else Error('Expected numeric register index error', Token.Pos);
262 end else Error('Expected register name starting with R character.', Token.Pos);
263 end else Error('Expected numeric register index error', Token.Pos);
264 end else Error('Expected register name starting with R character.', Token.Pos);
265 Parser.Expect(tkSpecialSymbol, ')');
266 end else
267 end;
268 end;
269 if not Result then Parser.Pos := LastPos;
270end;
271
272function TAssembler.ParseLabel: Boolean;
273var
274 LastPos: TParserPos;
275 Token: TToken;
276 Addr: Integer;
277begin
278 Result := False;
279 LastPos := Parser.Pos;
280 Token := Parser.ReadNext;
281 if Parser.CheckNextAndRead(tkSpecialSymbol, ':') then begin
282 Result := True;
283 if not Labels.TryGetValue(Token.Value, Addr) then begin
284 Labels.Add(Token.Value, Memory.Position);
285 end else Error('Duplicate label ' + Token.Value + '.', Token.Pos);
286 end;
287 if not Result then Parser.Pos := LastPos;
288end;
289
290procedure TAssembler.LoadFromFile(FileName: string);
291var
292 Lines: TStringList;
293begin
294 Lines := TStringList.Create;
295 try
296 Lines.LoadFromFile(FileName);
297 Compile(Lines.Text);
298 finally
299 Lines.Free;
300 end;
301end;
302
303function TAssembler.ParseStr(var Text: string; Separator: string): string;
304var
305 P: Integer;
306begin
307 P := Pos(Separator, Text);
308 if P > 0 then begin
309 Result := Trim(Copy(Text, 1, P - 1));
310 Text := Trim(Copy(Text, P + 1, MaxInt));
311 end else begin
312 Result := Trim(Text);
313 Text := '';
314 end;
315end;
316
317constructor TAssembler.Create;
318begin
319 Parser := TParser.Create;
320 Parser.OnError := Error;
321 Message := TMessages.Create;
322 Memory := TMemory.Create;
323 InstructionSet := TInstructionSet.Create;
324 Labels := TDictionary<string, Integer>.Create;
325 LabelRefs := TList<TLabelRef>.Create;
326 Variables := TDictionary<string, Integer>.Create;
327end;
328
329destructor TAssembler.Destroy;
330begin
331 FreeAndNil(Variables);
332 FreeAndNil(Labels);
333 FreeAndNil(LabelRefs);
334 FreeAndNil(InstructionSet);
335 FreeAndNil(Memory);
336 FreeAndNil(Message);
337 FreeAndNil(Parser);
338 inherited;
339end;
340
341end.
342
Note: See TracBrowser for help on using the repository browser.