source: tags/1.0.0/Target/UTargetInterpretter.pas

Last change on this file was 96, checked in by chronos, 6 years ago
  • Added: Theming support.
  • Modified: Items in Options dialog divided to two pages.
File size: 12.9 KB
Line 
1unit UTargetInterpretter;
2
3{$mode Delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, Dialogs, Forms, UTarget, UBFTarget;
9
10type
11 TTargetInterpretter = class;
12
13 { TTargetInterpretterThread }
14
15 TTargetInterpretterThread = class(TThread)
16 private
17 FNewState: TRunState;
18 procedure DoSetState;
19 procedure SetStateSafe(State: TRunState);
20 public
21 Parent: TTargetInterpretter;
22 procedure Execute; override;
23 end;
24
25 TCommandHandler = procedure of object;
26
27 { TTargetInterpretter }
28
29 TTargetInterpretter = class(TBFTarget)
30 private
31 FThreadState: Boolean;
32 FThread: TTargetInterpretterThread;
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 protected
49 procedure SetState(AValue: TRunState); override;
50 function GetTargetCode: string; override;
51 function GetExecutionPosition: Integer; override;
52 public
53 FProgramBreakpoints: array of Boolean;
54 SourceBreakpoint: array of Boolean;
55 Memory: array of Integer;
56 MemoryPosition: Integer;
57 Output: string;
58 OutputPosition: Integer;
59 Input: string;
60 InputPosition: Integer;
61 procedure OptimizeSource; override;
62 procedure Reset; override;
63 procedure Compile; override;
64 procedure Run; override;
65 procedure Pause; override;
66 procedure Stop; override;
67 procedure StepInto; override;
68 procedure StepOver; override;
69 procedure StepOut; override;
70 procedure RunToCursor(Pos: Integer); override;
71 constructor Create; override;
72 destructor Destroy; override;
73 property StepCount: Integer read FStepCount;
74 end;
75
76const
77 BrainFuckCommandText: array[TMachineCommand] of Char = (
78 ' ', '+', '-', '>', '<', '.', ',', '[', ']', '@', '=', '*');
79
80
81implementation
82
83resourcestring
84 SProgramLowerLimit = 'Program run over lower limit';
85 SProgramUpperLimit = 'Program run over upper limit';
86 SJumpTableInsistent = 'Jump table is inconsistent';
87 SJumpTableColision = 'Jump table colision';
88 SProgramNotRunning = 'Program not running';
89 SUnsupportedCommand = 'Unsupported command';
90
91{ TTargetInterpretterThread }
92
93procedure TTargetInterpretterThread.Execute;
94var
95 BreakPoint: TBreakPoint;
96begin
97 with Parent do
98 repeat
99 while (FProgramIndex < Length(FProgram)) and (State <> rsStopped) do begin
100 if State = rsRunning then begin
101 if FProgramBreakpoints[FProgramIndex] then begin
102 BreakPoint := BreakPoints.SearchByTargetPos(FProgramIndex);
103 if BreakPoint.System then BreakPoints.Delete(BreakPoints.IndexOf(BreakPoint));
104 SetStateSafe(rsPaused);
105 end else begin
106 if Assigned(FCommandTable[FProgram[FProgramIndex].Command]) then
107 FCommandTable[FProgram[FProgramIndex].Command]
108 else raise Exception.Create(SUnsupportedCommand);
109 Inc(FProgramIndex);
110 Inc(FStepCount);
111 end;
112 end else
113 if State = rsPaused then Sleep(1);
114 end;
115 if State <> rsStopped then SetStateSafe(rsStopped);
116 until Terminated or (State = rsStopped);
117end;
118
119procedure TTargetInterpretterThread.DoSetState;
120begin
121 Parent.State := FNewState;
122end;
123
124procedure TTargetInterpretterThread.SetStateSafe(State: TRunState);
125begin
126 FNewState := State;
127 Synchronize(DoSetState);
128end;
129
130{ TTargetInterpretter }
131
132procedure TTargetInterpretter.SetState(AValue: TRunState);
133begin
134 if FState = AValue then Exit;
135 FState := AValue;
136 if Assigned(FOnChangeState) then FOnChangeState(Self);
137end;
138
139procedure TTargetInterpretter.SetThread(State: Boolean);
140begin
141 if FThreadState = State then Exit;
142 FThreadState := State;
143 if State then begin
144 FThread := TTargetInterpretterThread.Create(True);
145 FThread.Parent := Self;
146 FThread.FreeOnTerminate := False;
147 FThread.Start;
148 end else begin
149 FreeAndNil(FThread);
150 end;
151end;
152
153procedure TTargetInterpretter.PrepareJumpTable;
154var
155 Loop: array of Integer;
156 I: Integer;
157begin
158 for I := 0 to Length(FProgram) - 1 do begin
159 case FProgram[I].Command of
160 cmLoopStart: FProgram[I].Parameter := 0;
161 cmLoopEnd: FProgram[I].Parameter := 0;
162 end;
163 end;
164
165 SetLength(Loop, 0);
166 for I := 0 to Length(FProgram) - 1 do begin
167 case FProgram[I].Command of
168 cmLoopStart: begin
169 SetLength(Loop, Length(Loop) + 1);
170 Loop[High(Loop)] := I;
171 end;
172 cmLoopEnd: begin
173 if FProgram[I].Parameter > 0 then
174 raise Exception.Create(SJumpTableColision);
175 FProgram[I].Parameter := Loop[High(Loop)];
176 if FProgram[Loop[High(Loop)]].Parameter > 0 then
177 raise Exception.Create(SJumpTableColision);
178 FProgram[Loop[High(Loop)]].Parameter := I;
179 SetLength(Loop, Length(Loop) - 1);
180 end;
181 end;
182 end;
183 if Length(Loop) > 0 then raise Exception.Create(SJumpTableInsistent);
184end;
185
186procedure TTargetInterpretter.CommandInput;
187begin
188 while (InputPosition > Length(Input)) and (FState <> rsStopped) do begin
189 Sleep(1);
190 end;
191 if InputPosition <= Length(Input) then begin
192 Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] :=
193 Ord(Input[InputPosition]);
194 Inc(InputPosition);
195 end;
196end;
197
198procedure TTargetInterpretter.CommandOutput;
199begin
200 if OutputPosition > Length(Output) then
201 SetLength(Output, Length(Output) + 1 + Length(Output) div 4);
202 Output[OutputPosition] := Char(Memory[MemoryPosition +
203 FProgram[FProgramIndex].RelIndex]);
204 Inc(OutputPosition);
205end;
206
207procedure TTargetInterpretter.CommandLoopStart;
208begin
209 if Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] = 0 then
210 FProgramIndex := FProgram[FProgramIndex].Parameter;
211end;
212
213procedure TTargetInterpretter.CommandLoopEnd;
214begin
215 if Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] > 0 then
216 FProgramIndex := FProgram[FProgramIndex].Parameter - 1;
217end;
218
219procedure TTargetInterpretter.CommandInc;
220begin
221 Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] :=
222 ((Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] +
223 FProgram[FProgramIndex].Parameter) mod CellSize);
224end;
225
226procedure TTargetInterpretter.CommandDec;
227begin
228 Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] :=
229 ((Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] -
230 FProgram[FProgramIndex].Parameter) mod CellSize);
231end;
232
233procedure TTargetInterpretter.CommandPointerInc;
234begin
235 if MemoryPosition < MemorySize then Inc(MemoryPosition, FProgram[FProgramIndex].Parameter)
236 else raise Exception.Create(SProgramUpperLimit);
237 if (MemoryPosition + 1) > MemoryMaxUsed then
238 MemoryMaxUsed := MemoryPosition + 1;
239end;
240
241procedure TTargetInterpretter.CommandPointerDec;
242begin
243 if MemoryPosition > 0 then Dec(MemoryPosition, FProgram[FProgramIndex].Parameter)
244 else raise Exception.Create(SProgramLowerLimit);
245end;
246
247procedure TTargetInterpretter.CommandSet;
248begin
249 Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] :=
250 FProgram[FProgramIndex].Parameter mod CellSize;
251end;
252
253procedure TTargetInterpretter.CommandMultiply;
254begin
255 Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] :=
256 (Memory[MemoryPosition + FProgram[FProgramIndex].RelIndex] +
257 Memory[MemoryPosition] * FProgram[FProgramIndex].Parameter) mod CellSize;
258end;
259
260procedure TTargetInterpretter.Reset;
261var
262 I: Integer;
263begin
264 inherited;
265 SetLength(Memory, MemorySize);
266 PrepareJumpTable;
267 FProgramIndex := 0;
268 InputPosition := 1;
269 Output := '';
270 OutputPosition := 1;
271 MemoryPosition := 0;
272 MemoryMaxUsed := 1;
273 //FillChar(Pointer(Memory)^, Length(Memory), 0);
274 for I := 0 to Length(Memory) - 1 do
275 Memory[I] := 0;
276 FStepCount := 0;
277 PrepareBreakPoints;
278end;
279
280procedure TTargetInterpretter.Compile;
281begin
282 inherited;
283end;
284
285procedure TTargetInterpretter.PrepareBreakPoints;
286var
287 I: Integer;
288begin
289 SetLength(FProgramBreakpoints, Length(FProgram));
290 for I := 0 to High(FProgramBreakpoints) do
291 FProgramBreakpoints[I] := False;
292 for I := 0 to BreakPoints.Count - 1 do
293 if TBreakPoint(BreakPoints[I]).TargetAddress < Length(FProgramBreakpoints) then
294 FProgramBreakpoints[TBreakPoint(BreakPoints[I]).TargetAddress] := True;
295end;
296
297function TTargetInterpretter.GetTargetCode: string;
298var
299 I: Integer;
300begin
301 Result := '';
302 for I := 0 to Length(FProgram) - 1 do begin
303 Result := Result + BrainFuckCommandText[FProgram[I].Command];
304 if FProgram[I].Command in [cmInc, cmDec, cmPointerInc, cmPointerDec,
305 cmSet, cmMultipy] then begin
306 if FProgram[I].Parameter <> 1 then
307 Result := Result + IntToStr(FProgram[I].Parameter);
308 end;
309 if FProgram[I].RelIndex <> 0 then
310 Result := Result + 'R' + IntToStr(FProgram[I].RelIndex);
311 end;
312end;
313
314function TTargetInterpretter.GetExecutionPosition: Integer;
315begin
316 Result := FProgramIndex;
317end;
318
319procedure TTargetInterpretter.OptimizeSource;
320begin
321 inherited OptimizeSource;
322end;
323
324procedure TTargetInterpretter.Run;
325begin
326 PrepareBreakPoints;
327 if FState = rsStopped then begin
328 Reset;
329 SetThread(False);
330 SetThread(True);
331 State := rsRunning;
332 end else State := rsRunning;
333end;
334
335procedure TTargetInterpretter.Pause;
336begin
337 if State = rsRunning then State := rsPaused;
338end;
339
340procedure TTargetInterpretter.Stop;
341begin
342 State := rsStopped;
343 SetThread(False);
344end;
345
346procedure TTargetInterpretter.StepInto;
347var
348 Step: TDebugStep;
349begin
350 if State = rsPaused then begin
351 Step := DebugSteps.SearchByTargetPos(FProgramIndex);
352 if Step.Operation = soStepOut then begin
353 BreakPoints.SetSystem(Step.TargetPosition + 1);
354 Step := DebugSteps.SearchByTargetPos(FProgram[Step.TargetPosition].Parameter);
355 BreakPoints.AddSystem(Step.TargetPosition);
356 end else
357 if Step.Operation = soStepIn then begin
358 BreakPoints.SetSystem(Step.TargetPosition + 1);
359 Step := DebugSteps.SearchByTargetPos(FProgram[Step.TargetPosition].Parameter);
360 BreakPoints.AddSystem(Step.TargetPosition);
361 end else BreakPoints.SetSystem(Step.TargetPosition + 1);
362 Run;
363 end else raise Exception.Create(SProgramNotRunning);
364end;
365
366procedure TTargetInterpretter.StepOver;
367var
368 Step: TDebugStep;
369begin
370 if State = rsPaused then begin
371 Step := DebugSteps.SearchByTargetPos(FProgramIndex);
372 if Step.Operation = soStepOut then begin
373 BreakPoints.SetSystem(Step.TargetPosition + 1);
374 Step := DebugSteps.SearchByTargetPos(FProgram[Step.TargetPosition].Parameter);
375 BreakPoints.AddSystem(Step.TargetPosition);
376 end else
377 if Step.Operation = soStepIn then begin
378 Step := DebugSteps.SearchByTargetPos(FProgram[Step.TargetPosition].Parameter);
379 BreakPoints.SetSystem(Step.TargetPosition + 1);
380 end else BreakPoints.SetSystem(Step.TargetPosition + 1);
381 Run;
382 end else raise Exception.Create(SProgramNotRunning);
383end;
384
385procedure TTargetInterpretter.StepOut;
386var
387 Step: TDebugStep;
388 StepIndex: Integer;
389 Nesting: Integer;
390begin
391 if State = rsPaused then begin
392 Step := DebugSteps.SearchByTargetPos(FProgramIndex);
393 StepIndex := DebugSteps.IndexOf(Step);
394 Nesting := 1;
395 while (StepIndex < DebugSteps.Count) and (Nesting > 0) do begin
396 if TDebugStep(DebugSteps[StepIndex]).Operation = soStepIn then Inc(Nesting);
397 if TDebugStep(DebugSteps[StepIndex]).Operation = soStepOut then Dec(Nesting);
398 Inc(StepIndex);
399 end;
400 if StepIndex < DebugSteps.Count then begin
401 Breakpoints.SetSystem(TDebugStep(DebugSteps[StepIndex]).TargetPosition);
402 end;
403 Run;
404 end else raise Exception.Create(SProgramNotRunning);
405end;
406
407procedure TTargetInterpretter.RunToCursor(Pos: Integer);
408begin
409 Breakpoints.SetSystem(Pos);
410 Run;
411end;
412
413constructor TTargetInterpretter.Create;
414begin
415 inherited;
416 Name := 'Interpretter';
417 ImageIndex := 25;
418 Capabilities := [tcRun, tcPause, tcStop, tcCompile, tcStepOut, tcStepInto,
419 tcStepOver, tcRunToCursor];
420 // Base commands
421 FCommandTable[cmInc] := CommandInc;
422 FCommandTable[cmDec] := CommandDec;
423 FCommandTable[cmPointerInc] := CommandPointerInc;
424 FCommandTable[cmPointerDec] := CommandPointerDec;
425 FCommandTable[cmOutput] := CommandOutput;
426 FCommandTable[cmInput] := CommandInput;
427 FCommandTable[cmLoopStart] := CommandLoopStart;
428 FCommandTable[cmLoopEnd] := CommandLoopEnd;
429 // Extended commands
430 FCommandTable[cmSet] := CommandSet;
431 FCommandTable[cmMultipy] := CommandMultiply;
432end;
433
434destructor TTargetInterpretter.Destroy;
435begin
436 FState := rsStopped;
437 SetThread(False);
438 inherited Destroy;
439end;
440
441end.
442
Note: See TracBrowser for help on using the repository browser.