source: trunk/Target/TargetInterpreter.pas

Last change on this file was 152, checked in by chronos, 6 months ago
  • Fixed: A typo in interpreter target name.
File size: 13.7 KB
Line 
1unit TargetInterpreter;
2
3interface
4
5uses
6 Classes, SysUtils, Dialogs, Forms, Target, BFTarget, Math;
7
8type
9 TTargetInterpreter = class;
10
11 { TTargetInterpreterThread }
12
13 TTargetInterpreterThread = class(TThread)
14 private
15 FNewState: TRunState;
16 FMessage: string;
17 procedure DoMessage;
18 procedure DoSetState;
19 procedure SetStateSafe(State: TRunState);
20 public
21 Parent: TTargetInterpreter;
22 procedure Execute; override;
23 end;
24
25 TCommandHandler = procedure of object;
26
27 { TTargetInterpreter }
28
29 TTargetInterpreter = class(TBFTarget)
30 private
31 FThreadState: Boolean;
32 FThread: TTargetInterpreterThread;
33 FStepCount: Integer;
34 FCommandTable: array[TMachineCommand] of TCommandHandler;
35 procedure SetThread(State: Boolean);
36 procedure PrepareJumpTable;
37 procedure CommandInc;
38 procedure CommandDec;
39 procedure CommandPointerInc;
40 procedure CommandPointerDec;
41 procedure CommandInput;
42 procedure CommandOutput;
43 procedure CommandLoopStart;
44 procedure CommandLoopEnd;
45 procedure CommandSet;
46 procedure CommandMultiply;
47 procedure PrepareBreakPoints;
48 procedure CheckMemoryBounds(Address: Integer);
49 protected
50 procedure SetState(AValue: TRunState); override;
51 procedure EmitTargetCode;
52 function GetExecutionPosition: Integer; override;
53 public
54 FProgramBreakpoints: array of Boolean;
55 SourceBreakpoint: array of Boolean;
56 Memory: array of Integer;
57 MemoryPosition: Integer;
58 MemoryChanged: Boolean;
59 Output: string;
60 OutputPosition: Integer;
61 OutputChanged: Boolean;
62 Input: string;
63 InputPosition: Integer;
64 procedure OptimizeSource; override;
65 procedure Reset; override;
66 procedure Compile; override;
67 procedure Run; override;
68 procedure Pause; override;
69 procedure Stop; override;
70 procedure StepInto; override;
71 procedure StepOver; override;
72 procedure StepOut; override;
73 procedure RunToCursor(Pos: Integer); override;
74 constructor Create; override;
75 destructor Destroy; override;
76 property StepCount: Integer read FStepCount;
77 end;
78
79
80implementation
81
82resourcestring
83 SProgramLowerMemoryLimit = 'Program run over lower memory limit';
84 SProgramUpperMemoryLimit = 'Program run over upper memory limit';
85 SJumpTableInconsistent = 'Jump table is inconsistent';
86 SJumpTableCollision = 'Jump table collision';
87 SProgramNotRunning = 'Program not running';
88 SUnsupportedCommand = 'Unsupported command';
89 SBreakPointIndexError = 'Break point index error: %d';
90
91{ TTargetInterpreterThread }
92
93procedure TTargetInterpreterThread.Execute;
94var
95 BreakPoint: TBreakPoint;
96 Index: Integer;
97begin
98 try
99 with Parent do
100 repeat
101 while (FProgramIndex < FProgram.Count) and (State <> rsStopped) do begin
102 if State = rsRunning then begin
103 if FProgramBreakpoints[FProgramIndex] then begin
104 BreakPoint := BreakPoints.SearchByTargetPos(FProgramIndex);
105 if BreakPoint.System then begin
106 Index := BreakPoints.IndexOf(BreakPoint);
107 if Index <> -1 then BreakPoints.Delete(Index)
108 else raise Exception.Create(Format(SBreakPointIndexError, [Index]));
109 end;
110 SetStateSafe(rsPaused);
111 end else begin
112 if Assigned(FCommandTable[FProgram[FProgramIndex].Command]) then
113 FCommandTable[FProgram[FProgramIndex].Command]
114 else raise Exception.Create(SUnsupportedCommand);
115 Inc(FProgramIndex);
116 Inc(FStepCount);
117 end;
118 end else
119 if State = rsPaused then Sleep(1);
120 end;
121 if State <> rsStopped then SetStateSafe(rsStopped);
122 until Terminated or (State = rsStopped);
123
124 except
125 on E: Exception do begin
126 FMessage := E.Message;
127 Synchronize(DoMessage);
128 end;
129 end;
130end;
131
132procedure TTargetInterpreterThread.DoMessage;
133begin
134 Parent.SendMessage(FMessage);
135end;
136
137procedure TTargetInterpreterThread.DoSetState;
138begin
139 Parent.State := FNewState;
140end;
141
142procedure TTargetInterpreterThread.SetStateSafe(State: TRunState);
143begin
144 if Parent.State = State then Exit;
145 FNewState := State;
146 Synchronize(DoSetState);
147end;
148
149{ TTargetInterpreter }
150
151procedure TTargetInterpreter.SetState(AValue: TRunState);
152begin
153 if FState = AValue then Exit;
154 FState := AValue;
155 if Assigned(FOnChangeState) then FOnChangeState(Self);
156end;
157
158procedure TTargetInterpreter.SetThread(State: Boolean);
159begin
160 if FThreadState = State then Exit;
161 FThreadState := State;
162 if State then begin
163 FThread := TTargetInterpreterThread.Create(True);
164 FThread.Parent := Self;
165 FThread.FreeOnTerminate := False;
166 FThread.Start;
167 end else begin
168 FreeAndNil(FThread);
169 end;
170end;
171
172procedure TTargetInterpreter.PrepareJumpTable;
173type
174 TArrayOfInteger = array of Integer;
175var
176 Loop: TArrayOfInteger;
177 I: Integer;
178begin
179 for I := 0 to FProgram.Count - 1 do begin
180 case FProgram[I].Command of
181 cmLoopStart: FProgram.Operations[I].Parameter := 0;
182 cmLoopEnd: FProgram.Operations[I].Parameter := 0;
183 end;
184 end;
185
186 Loop := Default(TArrayOfInteger);
187 for I := 0 to FProgram.Count - 1 do begin
188 case FProgram[I].Command of
189 cmLoopStart: begin
190 SetLength(Loop, Length(Loop) + 1);
191 Loop[High(Loop)] := I;
192 end;
193 cmLoopEnd: begin
194 if FProgram[I].Parameter > 0 then
195 raise Exception.Create(SJumpTableCollision);
196 FProgram.Operations[I].Parameter := Loop[High(Loop)];
197 if FProgram[Loop[High(Loop)]].Parameter > 0 then
198 raise Exception.Create(SJumpTableCollision);
199 FProgram.Operations[Loop[High(Loop)]].Parameter := I;
200 SetLength(Loop, Length(Loop) - 1);
201 end;
202 end;
203 end;
204 if Length(Loop) > 0 then raise Exception.Create(SJumpTableInconsistent);
205end;
206
207procedure TTargetInterpreter.CommandInput;
208var
209 Addr: Integer;
210begin
211 Addr := MemoryPosition + FProgram[FProgramIndex].RelIndex;
212 while (InputPosition > Length(Input)) and (FState <> rsStopped) do begin
213 Sleep(1);
214 end;
215 if InputPosition <= Length(Input) then begin
216 Memory[Addr] := Ord(Input[InputPosition]);
217 Inc(InputPosition);
218 MemoryMaxUsedAddr := Max(Addr, MemoryMaxUsedAddr);
219 MemoryChanged := True;
220 end;
221end;
222
223procedure TTargetInterpreter.CommandOutput;
224begin
225 if OutputPosition > Length(Output) then
226 SetLength(Output, Length(Output) + 1);
227 Output[OutputPosition] := Char(Memory[MemoryPosition +
228 FProgram[FProgramIndex].RelIndex]);
229 Inc(OutputPosition);
230 OutputChanged := True;
231end;
232
233procedure TTargetInterpreter.CommandLoopStart;
234begin
235 if Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] = 0 then
236 FProgramIndex := FProgram[FProgramIndex].Parameter - 1;
237end;
238
239procedure TTargetInterpreter.CommandLoopEnd;
240begin
241 if Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] > 0 then
242 FProgramIndex := FProgram[FProgramIndex].Parameter - 1;
243end;
244
245procedure TTargetInterpreter.CommandInc;
246var
247 Addr: Integer;
248begin
249 Addr := MemoryPosition + FProgram[FProgramIndex].RelIndex;
250 Memory[Addr] := ((Memory[Addr] + FProgram[FProgramIndex].Parameter) mod CellSize);
251 MemoryMaxUsedAddr := Max(Addr, MemoryMaxUsedAddr);
252 MemoryChanged := True;
253end;
254
255procedure TTargetInterpreter.CommandDec;
256var
257 Addr: Integer;
258begin
259 Addr := MemoryPosition + FProgram[FProgramIndex].RelIndex;
260 Memory[Addr] := ((Memory[Addr] - FProgram[FProgramIndex].Parameter) mod CellSize);
261 MemoryMaxUsedAddr := Max(Addr, MemoryMaxUsedAddr);
262 MemoryChanged := True;
263end;
264
265procedure TTargetInterpreter.CommandPointerInc;
266begin
267 if MemoryPosition < MemorySize then
268 Inc(MemoryPosition, FProgram[FProgramIndex].Parameter)
269 else raise Exception.Create(SProgramUpperMemoryLimit);
270end;
271
272procedure TTargetInterpreter.CommandPointerDec;
273begin
274 if MemoryPosition > 0 then
275 Dec(MemoryPosition, FProgram[FProgramIndex].Parameter)
276 else raise Exception.Create(SProgramLowerMemoryLimit);
277end;
278
279procedure TTargetInterpreter.CommandSet;
280var
281 Addr: Integer;
282begin
283 Addr := MemoryPosition + FProgram[FProgramIndex].RelIndex;
284 CheckMemoryBounds(Addr);
285 Memory[Addr] := FProgram[FProgramIndex].Parameter mod CellSize;
286 MemoryMaxUsedAddr := Max(Addr, MemoryMaxUsedAddr);
287 MemoryChanged := True;
288end;
289
290procedure TTargetInterpreter.CommandMultiply;
291var
292 Addr: Integer;
293begin
294 Addr := MemoryPosition + FProgram[FProgramIndex].RelIndex;
295 CheckMemoryBounds(Addr);
296 Memory[Addr] := (Memory[Addr] + Memory[MemoryPosition] *
297 FProgram[FProgramIndex].Parameter) mod CellSize;
298 MemoryMaxUsedAddr := Max(Addr, MemoryMaxUsedAddr);
299 MemoryChanged := True;
300end;
301
302procedure TTargetInterpreter.Reset;
303var
304 I: Integer;
305begin
306 inherited;
307 SetLength(Memory, MemorySize);
308 PrepareJumpTable;
309 FProgramIndex := 0;
310 InputPosition := 1;
311 Output := '';
312 OutputPosition := 1;
313 MemoryPosition := 0;
314 MemoryMaxUsedAddr := 0;
315 //FillChar(Pointer(Memory)^, Length(Memory), 0);
316 for I := 0 to Length(Memory) - 1 do
317 Memory[I] := 0;
318 MemoryChanged := True;
319 OutputChanged := True;
320 FStepCount := 0;
321 PrepareBreakPoints;
322end;
323
324procedure TTargetInterpreter.Compile;
325begin
326 inherited;
327 EmitTargetCode;
328end;
329
330procedure TTargetInterpreter.PrepareBreakPoints;
331var
332 I: Integer;
333begin
334 SetLength(FProgramBreakpoints, FProgram.Count);
335 for I := 0 to High(FProgramBreakpoints) do
336 FProgramBreakpoints[I] := False;
337 for I := 0 to BreakPoints.Count - 1 do
338 if BreakPoints[I].TargetAddress < Length(FProgramBreakpoints) then
339 FProgramBreakpoints[BreakPoints[I].TargetAddress] := True;
340end;
341
342procedure TTargetInterpreter.CheckMemoryBounds(Address: Integer);
343begin
344 if Address < 0 then raise Exception.Create(SProgramLowerMemoryLimit);
345 if Address >= MemorySize then raise Exception.Create(SProgramUpperMemoryLimit);
346end;
347
348procedure TTargetInterpreter.EmitTargetCode;
349var
350 I: Integer;
351 Code: string;
352 TargetIndex: Integer;
353 Step: TDebugStep;
354begin
355 TargetIndex := 0;
356 FTargetCode := '';
357 for I := 0 to FProgram.Count - 1 do begin
358 Code := GetOperationText(FProgram[I]);
359 FTargetCode := FTargetCode + Code;
360 if DebugEnabled then begin
361 Step := DebugSteps.SearchByProgramPos(I);
362 if Assigned(Step) then begin
363 Step.TargetPosition := TargetIndex;
364 end;// else
365 // raise Exception.Create(Format('Program index %d missing debug step.', [I]));
366 end;
367 Inc(TargetIndex, Length(Code));
368 end;
369end;
370
371function TTargetInterpreter.GetExecutionPosition: Integer;
372begin
373 Result := FProgramIndex;
374end;
375
376procedure TTargetInterpreter.OptimizeSource;
377begin
378 inherited;
379end;
380
381procedure TTargetInterpreter.Run;
382begin
383 PrepareBreakPoints;
384 if FState = rsStopped then begin
385 Reset;
386 SetThread(False);
387 SetThread(True);
388 State := rsRunning;
389 end else State := rsRunning;
390end;
391
392procedure TTargetInterpreter.Pause;
393begin
394 if State = rsRunning then State := rsPaused;
395end;
396
397procedure TTargetInterpreter.Stop;
398begin
399 State := rsStopped;
400 SetThread(False);
401end;
402
403procedure TTargetInterpreter.StepInto;
404var
405 Step: TDebugStep;
406begin
407 if State = rsPaused then begin
408 Step := DebugSteps.SearchByProgramPos(FProgramIndex);
409 if Step.Operation = soStepOut then begin
410 BreakPoints.SetSystem(Step.ProgramPosition + 1);
411 Step := DebugSteps.SearchByProgramPos(FProgram[Step.ProgramPosition].Parameter);
412 BreakPoints.AddSystem(Step.ProgramPosition);
413 end else
414 if Step.Operation = soStepIn then begin
415 BreakPoints.SetSystem(Step.ProgramPosition + 1);
416 Step := DebugSteps.SearchByProgramPos(FProgram[Step.ProgramPosition].Parameter);
417 BreakPoints.AddSystem(Step.ProgramPosition);
418 end else BreakPoints.SetSystem(Step.ProgramPosition + 1);
419 Run;
420 end else raise Exception.Create(SProgramNotRunning);
421end;
422
423procedure TTargetInterpreter.StepOver;
424var
425 Step: TDebugStep;
426begin
427 if State = rsPaused then begin
428 Step := DebugSteps.SearchByProgramPos(FProgramIndex);
429 if Step.Operation = soStepOut then begin
430 BreakPoints.SetSystem(Step.ProgramPosition + 1);
431 Step := DebugSteps.SearchByProgramPos(FProgram[Step.ProgramPosition].Parameter);
432 BreakPoints.AddSystem(Step.ProgramPosition);
433 end else
434 if Step.Operation = soStepIn then begin
435 Step := DebugSteps.SearchByProgramPos(FProgram[Step.ProgramPosition].Parameter);
436 BreakPoints.SetSystem(Step.ProgramPosition + 1);
437 end else BreakPoints.SetSystem(Step.ProgramPosition + 1);
438 Run;
439 end else raise Exception.Create(SProgramNotRunning);
440end;
441
442procedure TTargetInterpreter.StepOut;
443var
444 Step: TDebugStep;
445 StepIndex: Integer;
446 Nesting: Integer;
447begin
448 if State = rsPaused then begin
449 Step := DebugSteps.SearchByProgramPos(FProgramIndex);
450 StepIndex := DebugSteps.IndexOf(Step);
451 Nesting := 1;
452 while (StepIndex < DebugSteps.Count) and (Nesting > 0) do begin
453 if DebugSteps[StepIndex].Operation = soStepIn then Inc(Nesting);
454 if DebugSteps[StepIndex].Operation = soStepOut then Dec(Nesting);
455 Inc(StepIndex);
456 end;
457 if StepIndex < DebugSteps.Count then begin
458 Breakpoints.SetSystem(DebugSteps[StepIndex].ProgramPosition);
459 end;
460 Run;
461 end else raise Exception.Create(SProgramNotRunning);
462end;
463
464procedure TTargetInterpreter.RunToCursor(Pos: Integer);
465begin
466 Breakpoints.SetSystem(Pos);
467 Run;
468end;
469
470constructor TTargetInterpreter.Create;
471begin
472 inherited;
473 FName := 'Interpreter';
474 FImageIndex := 25;
475 FCapabilities := [tcRun, tcPause, tcStop, tcCompile, tcStepOut, tcStepInto,
476 tcStepOver, tcRunToCursor];
477 // Base commands
478 FCommandTable[cmInc] := CommandInc;
479 FCommandTable[cmDec] := CommandDec;
480 FCommandTable[cmPointerInc] := CommandPointerInc;
481 FCommandTable[cmPointerDec] := CommandPointerDec;
482 FCommandTable[cmOutput] := CommandOutput;
483 FCommandTable[cmInput] := CommandInput;
484 FCommandTable[cmLoopStart] := CommandLoopStart;
485 FCommandTable[cmLoopEnd] := CommandLoopEnd;
486 // Extended commands
487 FCommandTable[cmSet] := CommandSet;
488 FCommandTable[cmMultiply] := CommandMultiply;
489end;
490
491destructor TTargetInterpreter.Destroy;
492begin
493 FState := rsStopped;
494 SetThread(False);
495 inherited;
496end;
497
498end.
499
Note: See TracBrowser for help on using the repository browser.