source: branches/easy compiler/USourceExecutor.pas

Last change on this file was 149, checked in by chronos, 6 years ago
  • Fixed: Now arrays of string and integer are supported and executed correctly by executor.
  • Added: IfNotEqual command.
File size: 12.0 KB
Line 
1unit USourceExecutor;
2
3{$mode delphi}
4
5interface
6
7uses
8 Classes, SysUtils, USourceCode, Contnrs;
9
10type
11 TOutputEvent = procedure (Text: string) of object;
12 TInputEvent = function: string of object;
13
14 { TExecutorVariable }
15
16 TExecutorVariable = class
17 Variable: TSourceVariable;
18 Value: TSourceValue;
19
20 destructor Destroy; override;
21 end;
22
23 TExecutorVariables = class(TObjectList)
24 function Search(Variable: TSourceVariable): TExecutorVariable;
25 end;
26
27 TExecutorRepeat = class
28 RepeatCommand: TCommandRepeat;
29 Terminated: Boolean;
30 end;
31
32 { TExecutorRepeats }
33
34 TExecutorRepeats = class(TObjectList)
35 function Search(RepeatCommand: TCommandRepeat): TExecutorRepeat;
36 end;
37
38 { TSourceExecutor }
39
40 TSourceExecutor = class
41 private
42 FOnInput: TInputEvent;
43 FOnOutput: TOutputEvent;
44 Variables: TExecutorVariables;
45 RepeatBlocks: TExecutorRepeats;
46 SkipNext: Boolean;
47 procedure ExecuteAssign(CommandAssign: TCommandFunctionCall);
48 procedure ExecuteBeginEnd(BeginEnd: TCommandBeginEnd);
49 procedure ExecuteCommand(Command: TSourceCommand);
50 procedure ExecuteBreak(CommandBreak: TCommandBreak);
51 procedure ExecuteIfEqual(IfEqual: TCommandIfEqual);
52 procedure ExecuteIfNotEqual(IfNotEqual: TCommandIfNotEqual);
53 procedure ExecuteRepeat(CommandRepeat: TCommandRepeat);
54 function ReadValueReference(Reference: TSourceReference): TSourceValue;
55 function ReadVarReference(Reference: TSourceReference): TSourceValue;
56 public
57 constructor Create;
58 destructor Destroy; override;
59 procedure Execute(SourceCode: TSourceCode);
60 property OnOutput: TOutputEvent read FOnOutput write FOnOutput;
61 property OnInput: TInputEvent read FOnInput write FOnInput;
62 end;
63
64
65implementation
66
67{ TExecutorRepeat }
68
69function TExecutorRepeats.Search(RepeatCommand: TCommandRepeat): TExecutorRepeat;
70var
71 Item: TExecutorRepeat;
72begin
73 Result := nil;
74 for Item in Self do
75 if Item.RepeatCommand = RepeatCommand then begin
76 Result := Item;
77 Break;
78 end;
79end;
80
81{ TExecutorVariable }
82
83destructor TExecutorVariable.Destroy;
84begin
85 Value.Free;
86 inherited Destroy;
87end;
88
89
90{ TExecutorVariables }
91
92function TExecutorVariables.Search(Variable: TSourceVariable): TExecutorVariable;
93var
94 Item: TExecutorVariable;
95begin
96 Result := nil;
97 for Item in Self do
98 if Item.Variable = Variable then begin
99 Result := Item;
100 Break;
101 end;
102end;
103
104{ TSourceExecutor }
105
106constructor TSourceExecutor.Create;
107begin
108 Variables := TExecutorVariables.Create;
109 RepeatBlocks := TExecutorRepeats.Create;
110end;
111
112destructor TSourceExecutor.Destroy;
113begin
114 RepeatBlocks.Free;
115 Variables.Free;
116 inherited Destroy;
117end;
118
119procedure TSourceExecutor.Execute(SourceCode: TSourceCode);
120begin
121 SkipNext := False;
122 ExecuteBeginEnd(SourceCode.Main);
123end;
124
125function TSourceExecutor.ReadValueReference(Reference: TSourceReference): TSourceValue;
126var
127 ArrayIndex: TSourceValue;
128begin
129 Result := nil;
130 if Reference is TSourceReferenceConstant then begin
131 Result := TSourceReferenceConstant(Reference).Constant.Value;
132 end else
133 if Reference is TSourceReferenceVariable then begin
134 Result := Variables.Search(TSourceReferenceVariable(Reference).Variable).Value;
135 end else
136 if Reference is TSourceReferenceArray then begin
137 ArrayIndex := ReadValueReference(TSourceReferenceArray(Reference).Index);
138 if not (ArrayIndex is TSourceValueInteger) then
139 raise Exception.Create('Only integer array index supported');
140 Result := TSourceValue(TSourceValueArray(Variables.Search(TSourceReferenceArray(Reference).ArrayRef).Value).Items[TSourceValueInteger(ArrayIndex).Value]);
141 end else
142 raise Exception.Create('Unsupported reference');
143end;
144
145function TSourceExecutor.ReadVarReference(Reference: TSourceReference): TSourceValue;
146var
147 ArrayIndex: TSourceValue;
148 Variable: TSourceVariable;
149 ExecutorVar: TExecutorVariable;
150 I: Integer;
151begin
152 Result := nil;
153 if Reference is TSourceReferenceVariable then begin
154 Variable := TSourceReferenceVariable(Reference).Variable;
155 end else
156 if Reference is TSourceReferenceArray then begin
157 Variable := TSourceReferenceArray(Reference).ArrayRef;
158 end else
159 raise Exception.Create('Unsupported reference');
160
161 ExecutorVar := Variables.Search(Variable);
162 if not Assigned(ExecutorVar) then begin
163 ExecutorVar := TExecutorVariable.Create;
164 ExecutorVar.Variable := Variable;
165 Variables.Add(ExecutorVar);
166 ExecutorVar.Value := Variable.ValueType.GetValueType.Create;
167 end;
168 if Reference is TSourceReferenceVariable then begin
169 Result := ExecutorVar.Value;
170 end else
171 if Reference is TSourceReferenceArray then begin
172 ArrayIndex := ReadValueReference(TSourceReferenceArray(Reference).Index);
173 if not (ArrayIndex is TSourceValueInteger) then
174 raise Exception.Create('Only integer array index supported');
175 I := TSourceValueInteger(ArrayIndex).Value;
176 while TSourceValueArray(ExecutorVar.Value).Items.Count < (I + 1) do begin
177 TSourceValueArray(ExecutorVar.Value).Items.Add(TSourceTypeArray(TSourceReferenceArray(Reference).ArrayRef.ValueType).ItemType.GetValueType.Create);
178 end;
179 Result := TSourceValue(TSourceValueArray(ExecutorVar.Value).Items[I]);
180 end else
181 raise Exception.Create('Unsupported reference');
182end;
183
184procedure TSourceExecutor.ExecuteAssign(CommandAssign: TCommandFunctionCall);
185var
186 Dest: TSourceValue;
187 Source: TSourceValue;
188begin
189 with TCommandFunctionCall(CommandAssign) do begin
190 Dest := ReadVarReference(TSourceReference(Parameters[0]));
191 Source := ReadValueReference(TSourceReference(Parameters[1]));
192 Dest.Assign(Source);
193 end;
194end;
195
196procedure TSourceExecutor.ExecuteBeginEnd(BeginEnd: TCommandBeginEnd);
197var
198 IP: Integer;
199begin
200 IP := 0;
201 while IP < BeginEnd.Commands.Count do begin
202 if SkipNext then begin
203 SkipNext := False;
204 Inc(IP);
205 Continue;
206 end;
207 ExecuteCommand(TSourceCommand(BeginEnd.Commands[IP]));
208 Inc(IP);
209 end;
210end;
211
212procedure TSourceExecutor.ExecuteBreak(CommandBreak: TCommandBreak);
213var
214 RepeatBlock: TSourceCommand;
215 ExecutorRepeat: TExecutorRepeat;
216begin
217 RepeatBlock := CommandBreak.Parent;
218 while not (RepeatBlock is TCommandRepeat) and (RepeatBlock <> nil) do
219 RepeatBlock := RepeatBlock.Parent;
220 if Assigned(RepeatBlock) then begin
221 ExecutorRepeat := RepeatBlocks.Search(RepeatBlock as TCommandRepeat);
222 if Assigned(ExecutorRepeat) then begin
223 ExecutorRepeat.Terminated := True;
224 end else
225 raise Exception.Create('Missing executor repeat block');
226 end else
227 raise Exception.Create('Used break outside repeat loop');
228end;
229
230procedure TSourceExecutor.ExecuteIfEqual(IfEqual: TCommandIfEqual);
231var
232 Value1: TSourceValue;
233 Value2: TSourceValue;
234begin
235 Value1 := ReadValueReference(IfEqual.Reference1);
236 Value2 := ReadValueReference(IfEqual.Reference2);
237 if (Value1 is TSourceValueInteger) and (Value2 is TSourceValueInteger) then begin
238 if TSourceValueInteger(Value1).Value <> TSourceValueInteger(Value2).Value then
239 SkipNext := True;
240 end else
241 if (Value1 is TSourceValueString) and (Value2 is TSourceValueString) then begin
242 if TSourceValueString(Value1).Value <> TSourceValueString(Value2).Value then
243 SkipNext := True;
244 end else
245 raise Exception.Create('Unsupported types for comparison.');
246end;
247
248procedure TSourceExecutor.ExecuteIfNotEqual(IfNotEqual: TCommandIfNotEqual);
249var
250 Value1: TSourceValue;
251 Value2: TSourceValue;
252begin
253 Value1 := ReadValueReference(IfNotEqual.Reference1);
254 Value2 := ReadValueReference(IfNotEqual.Reference2);
255 if (Value1 is TSourceValueInteger) and (Value2 is TSourceValueInteger) then begin
256 if TSourceValueInteger(Value1).Value = TSourceValueInteger(Value2).Value then
257 SkipNext := True;
258 end else
259 if (Value1 is TSourceValueString) and (Value2 is TSourceValueString) then begin
260 if TSourceValueString(Value1).Value = TSourceValueString(Value2).Value then
261 SkipNext := True;
262 end else
263 raise Exception.Create('Unsupported types for comparison.');
264end;
265
266procedure TSourceExecutor.ExecuteRepeat(CommandRepeat: TCommandRepeat);
267var
268 RepeatBlock: TExecutorRepeat;
269begin
270 RepeatBlock := TExecutorRepeat.Create;
271 RepeatBlock.RepeatCommand := CommandRepeat;
272 RepeatBlock.Terminated := False;
273 RepeatBlocks.Add(RepeatBlock);
274 repeat
275 ExecuteCommand(CommandRepeat.Command);
276 until RepeatBlock.Terminated;
277 RepeatBlocks.Remove(RepeatBlock);
278end;
279
280procedure TSourceExecutor.ExecuteCommand(Command: TSourceCommand);
281var
282 Variable: TSourceVariable;
283 Value: TSourceValue;
284 ExecutorVar: TExecutorVariable;
285 Text: string;
286 IntValue: Integer;
287 Dest: TSourceValue;
288begin
289 if Command is TCommandFunctionCall then
290 with TCommandFunctionCall(Command) do begin
291 if Name = 'print' then begin
292 if Assigned(FOnOutput) then begin
293 Value := ReadValueReference(TSourceReference(Parameters[0]));
294 if Value is TSourceValueString then
295 FOnOutput(TSourceValueString(Value).Value)
296 else if Value is TSourceValueInteger then
297 FOnOutput(IntToStr(TSourceValueInteger(Value).Value))
298 else raise Exception.Create('Unsupported value type');
299 end;
300 end else
301 if Name = 'println' then begin
302 if Assigned(FOnOutput) then begin
303 Value := ReadValueReference(TSourceReference(Parameters[0]));
304 if Value is TSourceValueString then
305 FOnOutput(TSourceValueString(Value).Value + LineEnding)
306 else if Value is TSourceValueInteger then
307 FOnOutput(IntToStr(TSourceValueInteger(Value).Value) + LineEnding)
308 else raise Exception.Create('Unsupported value type');
309 end;
310 end else
311 if Name = 'inputln' then begin
312 if Assigned(FOnInput) then begin
313 Value := ReadVarReference(TSourceReference(Parameters[0]));
314 if Value is TSourceValueString then begin
315 TSourceValueString(Value).Value := FOnInput;
316 FOnOutput(TSourceValueString(Value).Value + LineEnding);
317 end else
318 if Value is TSourceValueInteger then begin
319 Text := FOnInput;
320 if TryStrToInt(Text, IntValue) then
321 TSourceValueInteger(Value).Value := IntValue
322 else TSourceValueInteger(Value).Value := 0;
323 FOnOutput(IntToStr(TSourceValueInteger(Value).Value) + LineEnding);
324 end else
325 raise Exception.Create('Unsupported value type');
326 end;
327 end else
328 if Name = 'assign' then begin
329 ExecuteAssign(TCommandFunctionCall(Command));
330 end else
331 if Name = 'increment' then begin
332 Dest := ReadVarReference(TSourceReference(Parameters[0]));
333 Value := ReadValueReference(TSourceReference(Parameters[1]));
334 if (Dest is TSourceValueInteger) and (Value is TSourceValueInteger) then
335 Inc(TSourceValueInteger(Dest).Value, TSourceValueInteger(Value).Value)
336 else raise Exception.Create('Wrong type for increment');
337 end else
338 if Name = 'decrement' then begin
339 Dest := ReadVarReference(TSourceReference(Parameters[0]));
340 Value := ReadValueReference(TSourceReference(Parameters[1]));
341 if (Dest is TSourceValueInteger) and (Value is TSourceValueInteger) then
342 Dec(TSourceValueInteger(Dest).Value, TSourceValueInteger(Value).Value)
343 else raise Exception.Create('Wrong type for increment');
344 end else
345 raise Exception.Create('Unsupported function: ' + TCommandFunctionCall(Command).Name);
346 end else
347 if Command is TCommandBeginEnd then begin
348 ExecuteBeginEnd(TCommandBeginEnd(Command));
349 end else
350 if Command is TCommandBreak then begin
351 ExecuteBreak(TCommandBreak(Command));
352 end else
353 if Command is TCommandIfEqual then begin
354 ExecuteIfEqual(TCommandIfEqual(Command));
355 end else
356 if Command is TCommandIfNotEqual then begin
357 ExecuteIfNotEqual(TCommandIfNotEqual(Command));
358 end else
359 if Command is TCommandRepeat then begin
360 ExecuteRepeat(Command as TCommandRepeat);
361 end else
362 raise Exception.Create('Unsupported instruction');
363end;
364
365
366end.
367
Note: See TracBrowser for help on using the repository browser.