1 | unit Execute;
|
---|
2 |
|
---|
3 | interface
|
---|
4 |
|
---|
5 | uses
|
---|
6 | Source;
|
---|
7 |
|
---|
8 | type
|
---|
9 | TVariableValue = record
|
---|
10 | VarRef: PVariableRef;
|
---|
11 | BaseType: TBaseType;
|
---|
12 | case Integer of
|
---|
13 | btChar: (ValueChar: Char);
|
---|
14 | btInteger: (ValueInteger: Integer);
|
---|
15 | btShortString: (ValueString: ShortString);
|
---|
16 | btBoolean: (ValueBoolean: Boolean);
|
---|
17 | end;
|
---|
18 | PVariableValue = ^TVariableValue;
|
---|
19 |
|
---|
20 | { TVariableValues }
|
---|
21 |
|
---|
22 | TVariableValues = record
|
---|
23 | Items: array of TVariableValue;
|
---|
24 | function GetByName(Name: string): PVariableValue;
|
---|
25 | end;
|
---|
26 |
|
---|
27 | { TExecutionContext }
|
---|
28 |
|
---|
29 | TExecutionContext = record
|
---|
30 | VariableValues: TVariableValues;
|
---|
31 | procedure LoadFromVariables(Variables: PVariables);
|
---|
32 | end;
|
---|
33 | PExecutionContext = ^TExecutionContext;
|
---|
34 |
|
---|
35 | { TExecutionContexts }
|
---|
36 |
|
---|
37 | TExecutionContexts = record
|
---|
38 | Items: array of TExecutionContext;
|
---|
39 | function Last: PExecutionContext;
|
---|
40 | procedure Add;
|
---|
41 | procedure RemoveLast;
|
---|
42 | end;
|
---|
43 |
|
---|
44 | var
|
---|
45 | ExecutionContexts: TExecutionContexts;
|
---|
46 | ExecutionContextCurrent: PExecutionContext;
|
---|
47 | MainCode: PProgramCode;
|
---|
48 |
|
---|
49 | procedure ExecuteProgram(ProgramCode: PProgramCode);
|
---|
50 |
|
---|
51 |
|
---|
52 | implementation
|
---|
53 |
|
---|
54 | uses
|
---|
55 | Parser;
|
---|
56 |
|
---|
57 | procedure ExecuteCommand(Command: PCommand); forward;
|
---|
58 | procedure ExecuteGetValue(GetValue: PGetValue; Value: PVariableValue); forward;
|
---|
59 | procedure AssignVariable(Dest, Source: PVariableValue); forward;
|
---|
60 | procedure ExecuteExecution(Execution: PExecution; ReturnValue: PVariableValue); forward;
|
---|
61 |
|
---|
62 |
|
---|
63 | procedure ShowError(Text: string);
|
---|
64 | begin
|
---|
65 | WriteLn(Text);
|
---|
66 | Halt;
|
---|
67 | end;
|
---|
68 |
|
---|
69 | procedure ExecuteBeginEnd(BeginEnd: PBeginEnd);
|
---|
70 | var
|
---|
71 | I: Integer;
|
---|
72 | begin
|
---|
73 | for I := 0 to Length(BeginEnd^.Commands) - 1 do
|
---|
74 | ExecuteCommand(@BeginEnd^.Commands[I]);
|
---|
75 | end;
|
---|
76 |
|
---|
77 | procedure ShowErrorType(Variable: PVariableValue);
|
---|
78 | begin
|
---|
79 | ShowError('Not supported type')
|
---|
80 | end;
|
---|
81 |
|
---|
82 | procedure VariableAdd(Result, Operand: PVariableValue);
|
---|
83 | begin
|
---|
84 | case Result^.BaseType of
|
---|
85 | btBoolean: ShowErrorType(Result);
|
---|
86 | btChar: begin
|
---|
87 | Result.BaseType := btShortString;
|
---|
88 | Result.ValueString := Result.ValueString + Operand.ValueChar;
|
---|
89 | end;
|
---|
90 | btInteger: Result^.ValueInteger := Result^.ValueInteger + Operand^.ValueInteger;
|
---|
91 | btShortString: begin
|
---|
92 | if Operand^.BaseType = btShortString then
|
---|
93 | Result^.ValueString := Result^.ValueString + Operand^.ValueString
|
---|
94 | else if Operand^.BaseType = btChar then
|
---|
95 | Result^.ValueString := Result^.ValueString + Operand^.ValueChar
|
---|
96 | else ShowErrorType(Result);
|
---|
97 | end;
|
---|
98 | end;
|
---|
99 | end;
|
---|
100 |
|
---|
101 | procedure VariableNot(Result, Operand: PVariableValue);
|
---|
102 | begin
|
---|
103 | case Result^.BaseType of
|
---|
104 | btBoolean: Result^.ValueBoolean := not Operand^.ValueBoolean;
|
---|
105 | btChar: ShowErrorType(Result);
|
---|
106 | btInteger: ShowErrorType(Result);
|
---|
107 | btShortString: ShowErrorType(Result);
|
---|
108 | end;
|
---|
109 | end;
|
---|
110 |
|
---|
111 | procedure VariableSubtract(Result, Operand: PVariableValue);
|
---|
112 | begin
|
---|
113 | case Result^.BaseType of
|
---|
114 | btBoolean: ShowErrorType(Result);
|
---|
115 | btChar: ShowErrorType(Result);
|
---|
116 | btInteger: Result^.ValueInteger := Result^.ValueInteger - Operand^.ValueInteger;
|
---|
117 | btShortString: ShowErrorType(Result);
|
---|
118 | end;
|
---|
119 | end;
|
---|
120 |
|
---|
121 | procedure VariableAnd(Result, Operand: PVariableValue);
|
---|
122 | begin
|
---|
123 | case Result^.BaseType of
|
---|
124 | btBoolean: Result^.ValueBoolean := Result^.ValueBoolean and Operand^.ValueBoolean;
|
---|
125 | btChar: ShowErrorType(Result);
|
---|
126 | btInteger: Result^.ValueInteger := Result^.ValueInteger and Operand^.ValueInteger;
|
---|
127 | btShortString: ShowErrorType(Result);
|
---|
128 | end;
|
---|
129 | end;
|
---|
130 |
|
---|
131 | procedure VariableOr(Result, Operand: PVariableValue);
|
---|
132 | begin
|
---|
133 | case Result^.BaseType of
|
---|
134 | btBoolean: Result^.ValueBoolean := Result^.ValueBoolean or Operand^.ValueBoolean;
|
---|
135 | btChar: ShowErrorType(Result);
|
---|
136 | btInteger: Result^.ValueInteger := Result^.ValueInteger or Operand^.ValueInteger;
|
---|
137 | btShortString: ShowErrorType(Result);
|
---|
138 | end;
|
---|
139 | end;
|
---|
140 |
|
---|
141 | procedure VariableEqual(Result, Operand1, Operand2: PVariableValue);
|
---|
142 | begin
|
---|
143 | case Result^.BaseType of
|
---|
144 | btBoolean: Result^.ValueBoolean := Operand1^.ValueBoolean = Operand2^.ValueBoolean;
|
---|
145 | btChar: ShowErrorType(Result);
|
---|
146 | btInteger: ShowErrorType(Result);
|
---|
147 | btShortString: ShowErrorType(Result);
|
---|
148 | end;
|
---|
149 | end;
|
---|
150 |
|
---|
151 | procedure VariableNotEqual(Result, Operand1, Operand2: PVariableValue);
|
---|
152 | begin
|
---|
153 | case Result^.BaseType of
|
---|
154 | btBoolean: Result^.ValueBoolean := Operand1^.ValueBoolean <> Operand2^.ValueBoolean;
|
---|
155 | btChar: ShowErrorType(Result);
|
---|
156 | btInteger: ShowErrorType(Result);
|
---|
157 | btShortString: ShowErrorType(Result);
|
---|
158 | end;
|
---|
159 | end;
|
---|
160 |
|
---|
161 | procedure ExecuteExpression(Expression: PExpression; Value: PVariableValue);
|
---|
162 | var
|
---|
163 | I: Integer;
|
---|
164 | SubValue: TVariableValue;
|
---|
165 | Operand1: TVariableValue;
|
---|
166 | begin
|
---|
167 | if Expression^.NodeType = ntOperator then begin
|
---|
168 | I := 0;
|
---|
169 | while I < Length(Expression^.Items) do begin
|
---|
170 | if Expression^.Items[I].NodeType = ntOperator then begin
|
---|
171 | ExecuteExpression(@Expression^.Items[I], @SubValue);
|
---|
172 | end else
|
---|
173 | if Expression^.Items[I].NodeType = ntValue then begin
|
---|
174 | ExecuteGetValue(@Expression^.Items[I].Value, @SubValue);
|
---|
175 | end;
|
---|
176 |
|
---|
177 | if I = 0 then begin
|
---|
178 | // Just assign first operand
|
---|
179 | case Expression^.OperatorType of
|
---|
180 | opNot: begin
|
---|
181 | Value.BaseType := btBoolean;
|
---|
182 | VariableNot(Value, @SubValue);
|
---|
183 | end;
|
---|
184 | opAdd: AssignVariable(Value, @SubValue);
|
---|
185 | opSubtract: AssignVariable(Value, @SubValue);
|
---|
186 | opAnd: AssignVariable(Value, @SubValue);
|
---|
187 | opOr: AssignVariable(Value, @SubValue);
|
---|
188 | opEqual: AssignVariable(@Operand1, @SubValue);
|
---|
189 | opNotEqual: AssignVariable(@Operand1, @SubValue);
|
---|
190 | else ShowError('Unsupported operator type');
|
---|
191 | end;
|
---|
192 | end else begin
|
---|
193 | case Expression^.OperatorType of
|
---|
194 | opAdd: VariableAdd(Value, @SubValue);
|
---|
195 | opSubtract: VariableSubtract(Value, @SubValue);
|
---|
196 | opAnd: VariableAnd(Value, @SubValue);
|
---|
197 | opOr: VariableOr(Value, @SubValue);
|
---|
198 | opEqual: begin
|
---|
199 | Value.BaseType := btBoolean;
|
---|
200 | VariableEqual(Value, @Operand1, @SubValue);
|
---|
201 | end;
|
---|
202 | opNotEqual: begin
|
---|
203 | Value.BaseType := btBoolean;
|
---|
204 | VariableNotEqual(Value, @Operand1, @SubValue);
|
---|
205 | end
|
---|
206 | else ShowError('Unsupported operator type');
|
---|
207 | end;
|
---|
208 | end;
|
---|
209 | I := I + 1;
|
---|
210 | end;
|
---|
211 | end else
|
---|
212 | if Expression^.NodeType = ntValue then begin
|
---|
213 | ExecuteGetValue(@Expression^.Value, Value);
|
---|
214 | end else ShowError('Uninitialized expression');
|
---|
215 | end;
|
---|
216 |
|
---|
217 | function ExecuteGetValueBoolean(GetValue: PGetValue): Boolean;
|
---|
218 | var
|
---|
219 | Value: TVariableValue;
|
---|
220 | begin
|
---|
221 | ExecuteGetValue(GetValue, @Value);
|
---|
222 | Result := (Value.BaseType = btBoolean) and Value.ValueBoolean;
|
---|
223 | end;
|
---|
224 |
|
---|
225 | procedure ExecuteWhileDo(WhileDo: PWhileDo);
|
---|
226 | begin
|
---|
227 | while ExecuteGetValueBoolean(@WhileDo^.Condition) do
|
---|
228 | ExecuteCommand(@WhileDo^.Command);
|
---|
229 | end;
|
---|
230 |
|
---|
231 | procedure ExecuteIfThenElse(IfThenElse: PIfThenElse);
|
---|
232 | var
|
---|
233 | Condition: Boolean;
|
---|
234 | begin
|
---|
235 | Condition := ExecuteGetValueBoolean(@IfThenElse^.Condition);
|
---|
236 | if Condition then
|
---|
237 | ExecuteCommand(@IfThenElse^.DoThen);
|
---|
238 | if (IfThenElse^.DoElse.CmdType <> ctNone) and not Condition then
|
---|
239 | ExecuteCommand(@IfThenElse^.DoElse);
|
---|
240 | end;
|
---|
241 |
|
---|
242 | procedure AssignConstant(Variable: PVariableValue; Constant: PConstant);
|
---|
243 | begin
|
---|
244 | Variable^.BaseType := Constant^.DataType^.BaseType;
|
---|
245 | case Constant^.DataType^.BaseType of
|
---|
246 | btBoolean: Variable^.ValueBoolean := Constant^.ValueBoolean;
|
---|
247 | btInteger: Variable^.ValueInteger := Constant^.ValueInteger;
|
---|
248 | btShortString: Variable^.ValueString := Constant^.ValueString;
|
---|
249 | btChar: Variable^.ValueChar := Constant^.ValueChar;
|
---|
250 | end;
|
---|
251 | end;
|
---|
252 |
|
---|
253 | procedure ExecuteGetValue(GetValue: PGetValue; Value: PVariableValue);
|
---|
254 | begin
|
---|
255 | case GetValue.ReadType of
|
---|
256 | rtVariable: AssignVariable(Value, ExecutionContextCurrent^.VariableValues.GetByName(GetValue.VariableRef^.Variable^.Name));
|
---|
257 | //rtConstant: Value := ExecutionContextCurrent^.VariableValues.GetByName(GetValue.Variable^.Name);
|
---|
258 | rtExpression: ExecuteExpression(GetValue.Expression, Value);
|
---|
259 | rtValue: AssignConstant(Value, @GetValue.Value);
|
---|
260 | rtFunctionCall: ExecuteExecution(GetValue.FunctionCall, Value)
|
---|
261 | end;
|
---|
262 | end;
|
---|
263 |
|
---|
264 | procedure AssignVariable(Dest, Source: PVariableValue);
|
---|
265 | begin
|
---|
266 | Dest.BaseType := Source.BaseType;
|
---|
267 | case Dest.BaseType of
|
---|
268 | btInteger: Dest.ValueInteger := Source.ValueInteger;
|
---|
269 | btChar: Dest.ValueChar := Source.ValueChar;
|
---|
270 | btBoolean: Dest.ValueBoolean := Source.ValueBoolean;
|
---|
271 | btShortString: Dest.ValueString := Source.ValueString;
|
---|
272 | end;
|
---|
273 | end;
|
---|
274 |
|
---|
275 | function IsBuildInFunction(Name: string): Boolean;
|
---|
276 | begin
|
---|
277 | Result := (Name = 'WriteLn') or (Name = 'Eof') or (Name = 'Halt') or (Name = 'Read') or
|
---|
278 | (Name = 'Length') or (Name = 'SetLength');
|
---|
279 | end;
|
---|
280 |
|
---|
281 | procedure ExecuteBuildInSetResult(Execution: PExecution; TypeName: string);
|
---|
282 | var
|
---|
283 | DataType: PType;
|
---|
284 | begin
|
---|
285 | if Execution^.Func^.Variables.GetByName('Result') = nil then begin
|
---|
286 | DataType := MainCode.Types.GetByName(TypeName);
|
---|
287 | Execution^.Func^.Variables.Add(VariableCreate('Result', DataType));
|
---|
288 | SetLength(ExecutionContextCurrent^.VariableValues.Items, Length(ExecutionContextCurrent^.VariableValues.Items) + 1);
|
---|
289 | ExecutionContextCurrent^.VariableValues.Items[0].VarRef := @Execution^.Func^.Variables.Items[Length(Execution^.Func^.Variables.Items) - 1];
|
---|
290 | ExecutionContextCurrent^.VariableValues.Items[0].BaseType := btBoolean;
|
---|
291 | end;
|
---|
292 | end;
|
---|
293 |
|
---|
294 | procedure ExecuteBuildIn(Execution: PExecution);
|
---|
295 | begin
|
---|
296 | if Execution^.Func^.Name = 'WriteLn' then begin
|
---|
297 | WriteLn('|' + ExecutionContextCurrent^.VariableValues.GetByName('Text')^.ValueString)
|
---|
298 | end else
|
---|
299 | if Execution^.Func^.Name = 'Halt' then begin
|
---|
300 | Halt;
|
---|
301 | end else
|
---|
302 | if Execution^.Func^.Name = 'Read' then begin
|
---|
303 | ExecutionContextCurrent^.VariableValues.GetByName('Output')^.ValueChar := InnerText[InnerTextPos.Index];
|
---|
304 | InnerTextPos.Index := InnerTextPos.Index + 1;
|
---|
305 | end else
|
---|
306 | if Execution^.Func^.Name = 'Eof' then begin
|
---|
307 | ExecuteBuildInSetResult(Execution, 'Boolean');
|
---|
308 | ExecutionContextCurrent^.VariableValues.GetByName('Result')^.ValueBoolean := InnerTextPos.Index > Length(InnerText);
|
---|
309 | end else ShowError('Unsupported build-in function.');
|
---|
310 | end;
|
---|
311 |
|
---|
312 | procedure ExecuteExecution(Execution: PExecution; ReturnValue: PVariableValue);
|
---|
313 | var
|
---|
314 | I: Integer;
|
---|
315 | Param: PGetValue;
|
---|
316 | ParamValue: TVariableValue;
|
---|
317 | DestVar: PVariableValue;
|
---|
318 | NewContext: TExecutionContext;
|
---|
319 | begin
|
---|
320 | // Prepare new execution context
|
---|
321 | FillChar(NewContext, SizeOf(TExecutionContext), 0);
|
---|
322 | NewContext.LoadFromVariables(@Execution^.Func^.Variables);
|
---|
323 |
|
---|
324 | // Copy execution parameters to new execution context as local variables
|
---|
325 | for I := 0 to Length(Execution^.Func^.Parameters.Items) - 1 do begin
|
---|
326 | DestVar := NewContext.VariableValues.GetByName(
|
---|
327 | Execution^.Func^.Parameters.Items[I].Name);
|
---|
328 | Param := @Execution^.Parameters.Items[I];
|
---|
329 | ExecuteGetValue(Param, @ParamValue);
|
---|
330 | AssignVariable(DestVar, @ParamValue);
|
---|
331 | end;
|
---|
332 |
|
---|
333 | ExecutionContexts.Add;
|
---|
334 | ExecutionContexts.Items[Length(ExecutionContexts.Items) - 1] := NewContext;
|
---|
335 |
|
---|
336 | WriteLn('Executed ' + Execution^.Func^.Name);
|
---|
337 | if IsBuildInFunction(Execution^.Func^.Name) then ExecuteBuildIn(Execution)
|
---|
338 | else ExecuteBeginEnd(@Execution^.Func^.BeginEnd);
|
---|
339 | if (ReturnValue <> nil) and (Execution^.Func^.ReturnType <> nil) then
|
---|
340 | AssignVariable(ReturnValue, ExecutionContextCurrent^.VariableValues.GetByName('Result'));
|
---|
341 |
|
---|
342 | WriteLn('Return from ' + Execution^.Func^.Name);
|
---|
343 |
|
---|
344 | // Copy output parameters back to variable
|
---|
345 | NewContext := ExecutionContexts.Items[Length(ExecutionContexts.Items) - 1];
|
---|
346 | ExecutionContexts.RemoveLast;
|
---|
347 |
|
---|
348 | for I := 0 to Length(Execution^.Func^.Parameters.Items) - 1 do
|
---|
349 | if Execution^.Func^.Parameters.Items[I].Output then begin
|
---|
350 | DestVar := NewContext.VariableValues.GetByName(
|
---|
351 | Execution^.Func^.Parameters.Items[I].Name);
|
---|
352 | Param := @Execution^.Parameters.Items[I];
|
---|
353 | if (Param.ReadType = rtVariable) then
|
---|
354 | AssignVariable(ExecutionContextCurrent^.VariableValues.GetByName(Param.VariableRef^.Variable^.Name), DestVar)
|
---|
355 | else ShowError('Function var parameter can be only variable');
|
---|
356 | end;
|
---|
357 | end;
|
---|
358 |
|
---|
359 | procedure ExecuteAssignment(Assignment: PAssignment);
|
---|
360 | var
|
---|
361 | DestVariable: PVariableValue;
|
---|
362 | SrcVariable: TVariableValue;
|
---|
363 | begin
|
---|
364 | DestVariable := ExecutionContextCurrent^.VariableValues.GetByName(Assignment^.Destination^.Variable^.Name);
|
---|
365 | WriteLn('Assignment to ' + Assignment^.Destination^.Variable^.Name);
|
---|
366 | FillChar(SrcVariable, SizeOf(TVariableValue), 0);
|
---|
367 | ExecuteGetValue(@Assignment^.Source, @SrcVariable);
|
---|
368 | AssignVariable(DestVariable, @SrcVariable);
|
---|
369 | end;
|
---|
370 |
|
---|
371 | procedure ExecuteCommand(Command: PCommand);
|
---|
372 | begin
|
---|
373 | case Command^.CmdType of
|
---|
374 | ctBeginEnd: ExecuteBeginEnd(Command^.BeginEnd);
|
---|
375 | ctWhileDo: ExecuteWhileDo(Command^.WhileDo);
|
---|
376 | ctIfThenElse: ExecuteIfThenElse(Command^.IfThenElse);
|
---|
377 | ctExecution: ExecuteExecution(Command^.Execution, nil);
|
---|
378 | ctAssignment: ExecuteAssignment(Command^.Assignment);
|
---|
379 | end;
|
---|
380 | end;
|
---|
381 |
|
---|
382 | procedure ExecuteProgram(ProgramCode: PProgramCode);
|
---|
383 | begin
|
---|
384 | MainCode := ProgramCode;
|
---|
385 | ExecutionContexts.Add;
|
---|
386 | ExecutionContextCurrent^.LoadFromVariables(@ProgramCode^.Variables);
|
---|
387 | ExecuteBeginEnd(@ProgramCode^.BeginEnd);
|
---|
388 | end;
|
---|
389 |
|
---|
390 | { TVariableValues }
|
---|
391 |
|
---|
392 | function TVariableValues.GetByName(Name: string): PVariableValue;
|
---|
393 | var
|
---|
394 | I: Integer;
|
---|
395 | begin
|
---|
396 | I := 0;
|
---|
397 | while (I < Length(Items)) and (Items[I].VarRef^.Variable^.Name <> Name) do Inc(I);
|
---|
398 | if I < Length(Items) then Result := @Items[I]
|
---|
399 | else Result := nil;
|
---|
400 | end;
|
---|
401 |
|
---|
402 | { TExecutionContext }
|
---|
403 |
|
---|
404 | procedure TExecutionContext.LoadFromVariables(Variables: PVariables);
|
---|
405 | var
|
---|
406 | I: Integer;
|
---|
407 | begin
|
---|
408 | SetLength(VariableValues.Items, Length(Variables.Items));
|
---|
409 | for I := 0 to Length(Variables.Items) - 1 do begin
|
---|
410 | VariableValues.Items[I].BaseType := Variables.Items[I].DataType.BaseType;
|
---|
411 | VariableValues.Items[I].VarRef := @Variables.Items[I];
|
---|
412 | end;
|
---|
413 | end;
|
---|
414 |
|
---|
415 | { TExecutionContexts }
|
---|
416 |
|
---|
417 | function TExecutionContexts.Last: PExecutionContext;
|
---|
418 | begin
|
---|
419 | Result := @ExecutionContexts.Items[Length(ExecutionContexts.Items) - 1];
|
---|
420 | end;
|
---|
421 |
|
---|
422 | procedure TExecutionContexts.Add;
|
---|
423 | begin
|
---|
424 | SetLength(Items, Length(Items) + 1);
|
---|
425 | ExecutionContextCurrent := Last;
|
---|
426 | end;
|
---|
427 |
|
---|
428 | procedure TExecutionContexts.RemoveLast;
|
---|
429 | begin
|
---|
430 | SetLength(Items, Length(Items) - 1);
|
---|
431 | ExecutionContextCurrent := Last;
|
---|
432 | end;
|
---|
433 |
|
---|
434 |
|
---|
435 | end.
|
---|
436 |
|
---|