source: tags/1.2.0/Target/UTargetInterpretter.pas

Last change on this file was 137, checked in by chronos, 3 years ago
  • Fixed: Wrong index variable used in inc/dec merge optimization.
  • Fixed: Reload output if program is reset.
File size: 14.2 KB
Line 
1unit UTargetInterpretter;
2
3{$mode Delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, Dialogs, Forms, UTarget, UBFTarget, Math;
9
10type
11 TTargetInterpretter = class;
12
13 { TTargetInterpretterThread }
14
15 TTargetInterpretterThread = class(TThread)
16 private
17 FNewState: TRunState;
18 FMessage: string;
19 procedure DoMessage;
20 procedure DoSetState;
21 procedure SetStateSafe(State: TRunState);
22 public
23 Parent: TTargetInterpretter;
24 procedure Execute; override;
25 end;
26
27 TCommandHandler = procedure of object;
28
29 { TTargetInterpretter }
30
31 TTargetInterpretter = class(TBFTarget)
32 private
33 FThreadState: Boolean;
34 FThread: TTargetInterpretterThread;
35 FStepCount: Integer;
36 FCommandTable: array[TMachineCommand] of TCommandHandler;
37 procedure SetThread(State: Boolean);
38 procedure PrepareJumpTable;
39 procedure CommandInc;
40 procedure CommandDec;
41 procedure CommandPointerInc;
42 procedure CommandPointerDec;
43 procedure CommandInput;
44 procedure CommandOutput;
45 procedure CommandLoopStart;
46 procedure CommandLoopEnd;
47 procedure CommandSet;
48 procedure CommandMultiply;
49 procedure PrepareBreakPoints;
50 procedure CheckMemoryBounds(Address: Integer);
51 protected
52 procedure SetState(AValue: TRunState); override;
53 procedure EmitTargetCode;
54 function GetExecutionPosition: Integer; override;
55 public
56 FProgramBreakpoints: array of Boolean;
57 SourceBreakpoint: array of Boolean;
58 Memory: array of Integer;
59 MemoryPosition: Integer;
60 MemoryChanged: Boolean;
61 Output: string;
62 OutputPosition: Integer;
63 OutputChanged: Boolean;
64 Input: string;
65 InputPosition: Integer;
66 procedure OptimizeSource; override;
67 procedure Reset; override;
68 procedure Compile; override;
69 procedure Run; override;
70 procedure Pause; override;
71 procedure Stop; override;
72 procedure StepInto; override;
73 procedure StepOver; override;
74 procedure StepOut; override;
75 procedure RunToCursor(Pos: Integer); override;
76 constructor Create; override;
77 destructor Destroy; override;
78 property StepCount: Integer read FStepCount;
79 end;
80
81
82implementation
83
84resourcestring
85 SProgramLowerMemoryLimit = 'Program run over lower memory limit';
86 SProgramUpperMemoryLimit = 'Program run over upper memory limit';
87 SJumpTableInconsistent = 'Jump table is inconsistent';
88 SJumpTableCollision = 'Jump table collision';
89 SProgramNotRunning = 'Program not running';
90 SUnsupportedCommand = 'Unsupported command';
91 SBreakPointIndexError = 'Break point index error: %d';
92
93{ TTargetInterpretterThread }
94
95procedure TTargetInterpretterThread.Execute;
96var
97 BreakPoint: TBreakPoint;
98 Index: Integer;
99begin
100 try
101 with Parent do
102 repeat
103 while (FProgramIndex < FProgram.Count) and (State <> rsStopped) do begin
104 if State = rsRunning then begin
105 if FProgramBreakpoints[FProgramIndex] then begin
106 BreakPoint := BreakPoints.SearchByTargetPos(FProgramIndex);
107 if BreakPoint.System then begin
108 Index := BreakPoints.IndexOf(BreakPoint);
109 if Index <> -1 then BreakPoints.Delete(Index)
110 else raise Exception.Create(Format(SBreakPointIndexError, [Index]));
111 end;
112 SetStateSafe(rsPaused);
113 end else begin
114 if Assigned(FCommandTable[FProgram[FProgramIndex].Command]) then
115 FCommandTable[FProgram[FProgramIndex].Command]
116 else raise Exception.Create(SUnsupportedCommand);
117 Inc(FProgramIndex);
118 Inc(FStepCount);
119 end;
120 end else
121 if State = rsPaused then Sleep(1);
122 end;
123 if State <> rsStopped then SetStateSafe(rsStopped);
124 until Terminated or (State = rsStopped);
125
126 except
127 on E: Exception do begin
128 FMessage := E.Message;
129 Synchronize(DoMessage);
130 end;
131 end;
132end;
133
134procedure TTargetInterpretterThread.DoMessage;
135begin
136 Parent.SendMessage(FMessage);
137end;
138
139procedure TTargetInterpretterThread.DoSetState;
140begin
141 Parent.State := FNewState;
142end;
143
144procedure TTargetInterpretterThread.SetStateSafe(State: TRunState);
145begin
146 if Parent.State = State then Exit;
147 FNewState := State;
148 Synchronize(DoSetState);
149end;
150
151{ TTargetInterpretter }
152
153procedure TTargetInterpretter.SetState(AValue: TRunState);
154begin
155 if FState = AValue then Exit;
156 FState := AValue;
157 if Assigned(FOnChangeState) then FOnChangeState(Self);
158end;
159
160procedure TTargetInterpretter.SetThread(State: Boolean);
161begin
162 if FThreadState = State then Exit;
163 FThreadState := State;
164 if State then begin
165 FThread := TTargetInterpretterThread.Create(True);
166 FThread.Parent := Self;
167 FThread.FreeOnTerminate := False;
168 FThread.Start;
169 end else begin
170 FreeAndNil(FThread);
171 end;
172end;
173
174procedure TTargetInterpretter.PrepareJumpTable;
175var
176 Loop: array of Integer;
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 SetLength(Loop, 0);
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 TTargetInterpretter.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 TTargetInterpretter.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 TTargetInterpretter.CommandLoopStart;
234begin
235 if Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] = 0 then
236 FProgramIndex := FProgram[FProgramIndex].Parameter - 1;
237end;
238
239procedure TTargetInterpretter.CommandLoopEnd;
240begin
241 if Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] > 0 then
242 FProgramIndex := FProgram[FProgramIndex].Parameter - 1;
243end;
244
245procedure TTargetInterpretter.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 TTargetInterpretter.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 TTargetInterpretter.CommandPointerInc;
266begin
267 if MemoryPosition < MemorySize then
268 Inc(MemoryPosition, FProgram[FProgramIndex].Parameter)
269 else raise Exception.Create(SProgramUpperMemoryLimit);
270end;
271
272procedure TTargetInterpretter.CommandPointerDec;
273begin
274 if MemoryPosition > 0 then
275 Dec(MemoryPosition, FProgram[FProgramIndex].Parameter)
276 else raise Exception.Create(SProgramLowerMemoryLimit);
277end;
278
279procedure TTargetInterpretter.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 TTargetInterpretter.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 TTargetInterpretter.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 TTargetInterpretter.Compile;
325begin
326 inherited;
327 EmitTargetCode;
328end;
329
330procedure TTargetInterpretter.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 TTargetInterpretter.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 TTargetInterpretter.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 TTargetInterpretter.GetExecutionPosition: Integer;
372begin
373 Result := FProgramIndex;
374end;
375
376procedure TTargetInterpretter.OptimizeSource;
377begin
378 inherited;
379end;
380
381procedure TTargetInterpretter.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 TTargetInterpretter.Pause;
393begin
394 if State = rsRunning then State := rsPaused;
395end;
396
397procedure TTargetInterpretter.Stop;
398begin
399 State := rsStopped;
400 SetThread(False);
401end;
402
403procedure TTargetInterpretter.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 TTargetInterpretter.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 TTargetInterpretter.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 TTargetInterpretter.RunToCursor(Pos: Integer);
465begin
466 Breakpoints.SetSystem(Pos);
467 Run;
468end;
469
470constructor TTargetInterpretter.Create;
471begin
472 inherited;
473 FName := 'Interpretter';
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 TTargetInterpretter.Destroy;
492begin
493 FState := rsStopped;
494 SetThread(False);
495 inherited;
496end;
497
498end.
499
Note: See TracBrowser for help on using the repository browser.