source: branches/Machine/UCompiler.pas

Last change on this file was 86, checked in by chronos, 9 years ago
  • Added: Virtual machine test.
File size: 6.3 KB
Line 
1unit UCompiler;
2
3{$mode delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, Contnrs;
9
10type
11 TCodeLabel = class
12 Name: string;
13 Address: Integer;
14 end;
15
16 { TCodeLabels }
17
18 TCodeLabels = class(TObjectList)
19 function SearchByName(Name: string): TCodeLabel;
20 end;
21
22 TCodeDefine = class
23 Name: string;
24 Value: string;
25 end;
26
27 { TCodeDefines }
28
29 TCodeDefines = class(TObjectList)
30 function SearchByName(Name: string): TCodeDefine;
31 end;
32
33 { TCompiler }
34
35 TCompiler = class
36 private
37 Addr: Integer;
38 procedure Emit(Value: Integer);
39 procedure CompileParamPart(var Indir: Integer; Param: string);
40 procedure CompileParam(Num: Integer; Param: string);
41 procedure CompileParamDefine(var Indir: Integer; Param: string);
42 public
43 Code: array of Integer;
44 CodeLabels: TCodeLabels;
45 CodeDefines: TCodeDefines;
46 procedure Compile(Source: TStrings);
47 constructor Create;
48 destructor Destroy; override;
49 end;
50
51
52implementation
53
54uses
55 UMachine;
56
57{ TCodeDefines }
58
59function TCodeDefines.SearchByName(Name: string): TCodeDefine;
60var
61 I: Integer;
62begin
63 I := 0;
64 while (I < Count) and (TCodeDefine(Items[I]).Name <> Name) do Inc(I);
65 if I < Count then Result := TCodeDefine(Items[I])
66 else Result := nil;
67end;
68
69{ TCodeLabels }
70
71function TCodeLabels.SearchByName(Name: string): TCodeLabel;
72var
73 I: Integer;
74begin
75 I := 0;
76 while (I < Count) and (TCodeLabel(Items[I]).Name <> Name) do Inc(I);
77 if I < Count then Result := TCodeLabel(Items[I])
78 else Result := nil;
79end;
80
81procedure TCompiler.Emit(Value: Integer);
82begin
83 Code[Addr] := Value;
84 Inc(Addr);
85end;
86
87procedure TCompiler.CompileParamPart(var Indir: Integer; Param: string);
88var
89 Value: Integer;
90begin
91 if Indir = 0 then Emit(Integer(opParamSet))
92 else Emit(Integer(opParamIndirect));
93 if Indir = 0 then begin
94 if TryStrToInt(Param, Value) then Emit(StrToInt(Param))
95 else raise Exception.Create('Unsupported parameter value ''' + Param + '''');
96 end else begin
97 if Param = 'M' then Emit(Integer(atMemory))
98 else if Param = 'R' then Emit(Integer(atRegister))
99 else if Param = 'P' then Emit(Integer(atIOPort))
100 else if Param = 'S' then Emit(Integer(atSysRegister))
101 else begin
102 if TryStrToInt(Param, Value) then Emit(StrToInt(Param))
103 else raise Exception.Create('Unsupported parameter value ''' + Param + '''');
104 end;
105 end;
106 Inc(Indir);
107end;
108
109procedure TCompiler.CompileParam(Num: Integer; Param: string);
110var
111 Part: string;
112 I: Integer;
113 CodeLabel: TCodeLabel;
114 CodeDefine: TCodeDefine;
115begin
116 Param := Trim(Param);
117 if Num = 0 then Emit(Integer(opParamClearAll))
118 else Emit(Integer(opParamNext));
119 I := 0;
120 CodeLabel := CodeLabels.SearchByName(Param);
121 if Assigned(CodeLabel) then
122 CompileParamPart(I, IntToStr(CodeLabel.Address))
123 else begin
124 while Pos('^', Param) > 0 do begin
125 Part := Copy(Param, 1, Pos('^', Param) - 1);
126 Delete(Param, 1, Length(Part) + 1);
127 CompileParamDefine(I, Part);
128 end;
129 CompileParamDefine(I, Param);
130 end;
131end;
132
133procedure TCompiler.CompileParamDefine(var Indir: Integer; Param: string);
134var
135 CodeDefine: TCodeDefine;
136 Part: string;
137begin
138 CodeDefine := CodeDefines.SearchByName(Param);
139 if Assigned(CodeDefine) then begin
140 Param := CodeDefine.Value;
141 while Pos('^', Param) > 0 do begin
142 Part := Copy(Param, 1, Pos('^', Param) - 1);
143 Delete(Param, 1, Length(Part) + 1);
144 CompileParamPart(Indir, Part);
145 end;
146 CompileParamPart(Indir, Param);
147 end else
148 CompileParamPart(Indir, Param);
149end;
150
151procedure TCompiler.Compile(Source: TStrings);
152var
153 I: Integer;
154 Line: string;
155 Instruction: string;
156 Param1, Param2: string;
157 CodeLabel: TCodeLabel;
158 CodeDefine: TCodeDefine;
159begin
160 SetLength(Code, 10000);
161 Addr := 0;
162 for I := 0 to Source.Count - 1 do begin
163 Line := Trim(Source[I]);
164 if Pos(' ', Line) > 0 then begin
165 Instruction := Copy(Line, 1, Pos(' ', Line) - 1);
166 Delete(Line, 1, Length(Instruction) + 1);
167 end else Instruction := Line;
168
169 if Instruction = 'CP' then begin
170 Param1 := Copy(Line, 1, Pos(',', Line) - 1);
171 Delete(Line, 1, Length(Param1) + 1);
172 Param2 := Line;
173 CompileParam(0, Param1);
174 CompileParam(1, Param2);
175 Emit(Integer(opCopy));
176 end else
177 if Instruction = 'ADD' then begin
178 if Pos(',', Line) > 0 then begin
179 Param1 := Copy(Line, 1, Pos(',', Line) - 1);
180 Delete(Line, 1, Length(Param1) + 1);
181 Param2 := Line;
182 CompileParam(0, Param1);
183 CompileParam(1, Param2);
184 end else begin
185 CompileParam(0, Line);
186 end;
187 Emit(Integer(opAdd));
188 end else
189 if Instruction = 'SUB' then begin
190 if Pos(',', Line) > 0 then begin
191 Param1 := Copy(Line, 1, Pos(',', Line) - 1);
192 Delete(Line, 1, Length(Param1) + 1);
193 Param2 := Line;
194 CompileParam(0, Param1);
195 CompileParam(1, Param2);
196 end else begin
197 CompileParam(0, Line);
198 end;
199 Emit(Integer(opSub));
200 end else
201 if Instruction = 'SKIP' then begin
202 CompileParam(0, Line);
203 Emit(Integer(opSkip));
204 end else
205 if Instruction = 'HALT' then begin
206 Emit(Integer(opHalt));
207 end else
208 if Instruction = 'LABEL' then begin
209 CodeLabel := CodeLabels.SearchByName(Line);
210 if Assigned(CodeLabel) then raise Exception.Create('Label ''' + Line + ''' already used')
211 else begin
212 CodeLabel := TCodeLabel.Create;
213 CodeLabel.Name := Line;
214 CodeLabel.Address := Addr;
215 CodeLabels.Add(CodeLabel);
216 end;
217 end else
218 if Instruction = 'DEF' then begin
219 if Pos(' ', Line) > 0 then begin
220 Param1 := Copy(Line, 1, Pos(' ', Line) - 1);
221 Delete(Line, 1, Length(Param1) + 1);
222 Param2 := Line;
223 end else begin
224 Param1 := Line;
225 Param2 := '';
226 end;
227 CodeDefine := CodeDefines.SearchByName(Line);
228 if Assigned(CodeDefine) then raise Exception.Create('Define ''' + Line + ''' already used')
229 else begin
230 CodeDefine := TCodeDefine.Create;
231 CodeDefine.Name := Param1;
232 CodeDefine.Value := Param2;
233 CodeDefines.Add(CodeDefine);
234 end;
235 end;
236 end;
237end;
238
239constructor TCompiler.Create;
240begin
241 CodeLabels := TCodeLabels.Create;
242 CodeDefines := TCodeDefines.Create;
243end;
244
245destructor TCompiler.Destroy;
246begin
247 CodeLabels.Free;
248 CodeDefines.Free;
249 inherited Destroy;
250end;
251
252end.
253
Note: See TracBrowser for help on using the repository browser.