1 | unit USourceExecutor;
|
---|
2 |
|
---|
3 | {$mode delphi}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, USourceCode, Contnrs;
|
---|
9 |
|
---|
10 | type
|
---|
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 |
|
---|
65 | implementation
|
---|
66 |
|
---|
67 | { TExecutorRepeat }
|
---|
68 |
|
---|
69 | function TExecutorRepeats.Search(RepeatCommand: TCommandRepeat): TExecutorRepeat;
|
---|
70 | var
|
---|
71 | Item: TExecutorRepeat;
|
---|
72 | begin
|
---|
73 | Result := nil;
|
---|
74 | for Item in Self do
|
---|
75 | if Item.RepeatCommand = RepeatCommand then begin
|
---|
76 | Result := Item;
|
---|
77 | Break;
|
---|
78 | end;
|
---|
79 | end;
|
---|
80 |
|
---|
81 | { TExecutorVariable }
|
---|
82 |
|
---|
83 | destructor TExecutorVariable.Destroy;
|
---|
84 | begin
|
---|
85 | Value.Free;
|
---|
86 | inherited Destroy;
|
---|
87 | end;
|
---|
88 |
|
---|
89 |
|
---|
90 | { TExecutorVariables }
|
---|
91 |
|
---|
92 | function TExecutorVariables.Search(Variable: TSourceVariable): TExecutorVariable;
|
---|
93 | var
|
---|
94 | Item: TExecutorVariable;
|
---|
95 | begin
|
---|
96 | Result := nil;
|
---|
97 | for Item in Self do
|
---|
98 | if Item.Variable = Variable then begin
|
---|
99 | Result := Item;
|
---|
100 | Break;
|
---|
101 | end;
|
---|
102 | end;
|
---|
103 |
|
---|
104 | { TSourceExecutor }
|
---|
105 |
|
---|
106 | constructor TSourceExecutor.Create;
|
---|
107 | begin
|
---|
108 | Variables := TExecutorVariables.Create;
|
---|
109 | RepeatBlocks := TExecutorRepeats.Create;
|
---|
110 | end;
|
---|
111 |
|
---|
112 | destructor TSourceExecutor.Destroy;
|
---|
113 | begin
|
---|
114 | RepeatBlocks.Free;
|
---|
115 | Variables.Free;
|
---|
116 | inherited Destroy;
|
---|
117 | end;
|
---|
118 |
|
---|
119 | procedure TSourceExecutor.Execute(SourceCode: TSourceCode);
|
---|
120 | begin
|
---|
121 | SkipNext := False;
|
---|
122 | ExecuteBeginEnd(SourceCode.Main);
|
---|
123 | end;
|
---|
124 |
|
---|
125 | function TSourceExecutor.ReadValueReference(Reference: TSourceReference): TSourceValue;
|
---|
126 | var
|
---|
127 | ArrayIndex: TSourceValue;
|
---|
128 | begin
|
---|
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');
|
---|
143 | end;
|
---|
144 |
|
---|
145 | function TSourceExecutor.ReadVarReference(Reference: TSourceReference): TSourceValue;
|
---|
146 | var
|
---|
147 | ArrayIndex: TSourceValue;
|
---|
148 | Variable: TSourceVariable;
|
---|
149 | ExecutorVar: TExecutorVariable;
|
---|
150 | I: Integer;
|
---|
151 | begin
|
---|
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');
|
---|
182 | end;
|
---|
183 |
|
---|
184 | procedure TSourceExecutor.ExecuteAssign(CommandAssign: TCommandFunctionCall);
|
---|
185 | var
|
---|
186 | Dest: TSourceValue;
|
---|
187 | Source: TSourceValue;
|
---|
188 | begin
|
---|
189 | with TCommandFunctionCall(CommandAssign) do begin
|
---|
190 | Dest := ReadVarReference(TSourceReference(Parameters[0]));
|
---|
191 | Source := ReadValueReference(TSourceReference(Parameters[1]));
|
---|
192 | Dest.Assign(Source);
|
---|
193 | end;
|
---|
194 | end;
|
---|
195 |
|
---|
196 | procedure TSourceExecutor.ExecuteBeginEnd(BeginEnd: TCommandBeginEnd);
|
---|
197 | var
|
---|
198 | IP: Integer;
|
---|
199 | begin
|
---|
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;
|
---|
210 | end;
|
---|
211 |
|
---|
212 | procedure TSourceExecutor.ExecuteBreak(CommandBreak: TCommandBreak);
|
---|
213 | var
|
---|
214 | RepeatBlock: TSourceCommand;
|
---|
215 | ExecutorRepeat: TExecutorRepeat;
|
---|
216 | begin
|
---|
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');
|
---|
228 | end;
|
---|
229 |
|
---|
230 | procedure TSourceExecutor.ExecuteIfEqual(IfEqual: TCommandIfEqual);
|
---|
231 | var
|
---|
232 | Value1: TSourceValue;
|
---|
233 | Value2: TSourceValue;
|
---|
234 | begin
|
---|
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.');
|
---|
246 | end;
|
---|
247 |
|
---|
248 | procedure TSourceExecutor.ExecuteIfNotEqual(IfNotEqual: TCommandIfNotEqual);
|
---|
249 | var
|
---|
250 | Value1: TSourceValue;
|
---|
251 | Value2: TSourceValue;
|
---|
252 | begin
|
---|
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.');
|
---|
264 | end;
|
---|
265 |
|
---|
266 | procedure TSourceExecutor.ExecuteRepeat(CommandRepeat: TCommandRepeat);
|
---|
267 | var
|
---|
268 | RepeatBlock: TExecutorRepeat;
|
---|
269 | begin
|
---|
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);
|
---|
278 | end;
|
---|
279 |
|
---|
280 | procedure TSourceExecutor.ExecuteCommand(Command: TSourceCommand);
|
---|
281 | var
|
---|
282 | Variable: TSourceVariable;
|
---|
283 | Value: TSourceValue;
|
---|
284 | ExecutorVar: TExecutorVariable;
|
---|
285 | Text: string;
|
---|
286 | IntValue: Integer;
|
---|
287 | Dest: TSourceValue;
|
---|
288 | begin
|
---|
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');
|
---|
363 | end;
|
---|
364 |
|
---|
365 |
|
---|
366 | end.
|
---|
367 |
|
---|