source: branches/interpreter/interpreter4/Execute.pas

Last change on this file was 108, checked in by chronos, 7 years ago

*Modified: Better parsing of variable reference.

File size: 13.7 KB
Line 
1unit Execute;
2
3interface
4
5uses
6 Source;
7
8type
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
44var
45 ExecutionContexts: TExecutionContexts;
46 ExecutionContextCurrent: PExecutionContext;
47 MainCode: PProgramCode;
48
49procedure ExecuteProgram(ProgramCode: PProgramCode);
50
51
52implementation
53
54uses
55 Parser;
56
57procedure ExecuteCommand(Command: PCommand); forward;
58procedure ExecuteGetValue(GetValue: PGetValue; Value: PVariableValue); forward;
59procedure AssignVariable(Dest, Source: PVariableValue); forward;
60procedure ExecuteExecution(Execution: PExecution; ReturnValue: PVariableValue); forward;
61
62
63procedure ShowError(Text: string);
64begin
65 WriteLn(Text);
66 Halt;
67end;
68
69procedure ExecuteBeginEnd(BeginEnd: PBeginEnd);
70var
71 I: Integer;
72begin
73 for I := 0 to Length(BeginEnd^.Commands) - 1 do
74 ExecuteCommand(@BeginEnd^.Commands[I]);
75end;
76
77procedure ShowErrorType(Variable: PVariableValue);
78begin
79 ShowError('Not supported type')
80end;
81
82procedure VariableAdd(Result, Operand: PVariableValue);
83begin
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;
99end;
100
101procedure VariableNot(Result, Operand: PVariableValue);
102begin
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;
109end;
110
111procedure VariableSubtract(Result, Operand: PVariableValue);
112begin
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;
119end;
120
121procedure VariableAnd(Result, Operand: PVariableValue);
122begin
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;
129end;
130
131procedure VariableOr(Result, Operand: PVariableValue);
132begin
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;
139end;
140
141procedure VariableEqual(Result, Operand1, Operand2: PVariableValue);
142begin
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;
149end;
150
151procedure VariableNotEqual(Result, Operand1, Operand2: PVariableValue);
152begin
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;
159end;
160
161procedure ExecuteExpression(Expression: PExpression; Value: PVariableValue);
162var
163 I: Integer;
164 SubValue: TVariableValue;
165 Operand1: TVariableValue;
166begin
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');
215end;
216
217function ExecuteGetValueBoolean(GetValue: PGetValue): Boolean;
218var
219 Value: TVariableValue;
220begin
221 ExecuteGetValue(GetValue, @Value);
222 Result := (Value.BaseType = btBoolean) and Value.ValueBoolean;
223end;
224
225procedure ExecuteWhileDo(WhileDo: PWhileDo);
226begin
227 while ExecuteGetValueBoolean(@WhileDo^.Condition) do
228 ExecuteCommand(@WhileDo^.Command);
229end;
230
231procedure ExecuteIfThenElse(IfThenElse: PIfThenElse);
232var
233 Condition: Boolean;
234begin
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);
240end;
241
242procedure AssignConstant(Variable: PVariableValue; Constant: PConstant);
243begin
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;
251end;
252
253procedure ExecuteGetValue(GetValue: PGetValue; Value: PVariableValue);
254begin
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;
262end;
263
264procedure AssignVariable(Dest, Source: PVariableValue);
265begin
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;
273end;
274
275function IsBuildInFunction(Name: string): Boolean;
276begin
277 Result := (Name = 'WriteLn') or (Name = 'Eof') or (Name = 'Halt') or (Name = 'Read') or
278 (Name = 'Length') or (Name = 'SetLength');
279end;
280
281procedure ExecuteBuildInSetResult(Execution: PExecution; TypeName: string);
282var
283 DataType: PType;
284begin
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;
292end;
293
294procedure ExecuteBuildIn(Execution: PExecution);
295begin
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.');
310end;
311
312procedure ExecuteExecution(Execution: PExecution; ReturnValue: PVariableValue);
313var
314 I: Integer;
315 Param: PGetValue;
316 ParamValue: TVariableValue;
317 DestVar: PVariableValue;
318 NewContext: TExecutionContext;
319begin
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;
357end;
358
359procedure ExecuteAssignment(Assignment: PAssignment);
360var
361 DestVariable: PVariableValue;
362 SrcVariable: TVariableValue;
363begin
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);
369end;
370
371procedure ExecuteCommand(Command: PCommand);
372begin
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;
380end;
381
382procedure ExecuteProgram(ProgramCode: PProgramCode);
383begin
384 MainCode := ProgramCode;
385 ExecutionContexts.Add;
386 ExecutionContextCurrent^.LoadFromVariables(@ProgramCode^.Variables);
387 ExecuteBeginEnd(@ProgramCode^.BeginEnd);
388end;
389
390{ TVariableValues }
391
392function TVariableValues.GetByName(Name: string): PVariableValue;
393var
394 I: Integer;
395begin
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;
400end;
401
402{ TExecutionContext }
403
404procedure TExecutionContext.LoadFromVariables(Variables: PVariables);
405var
406 I: Integer;
407begin
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;
413end;
414
415{ TExecutionContexts }
416
417function TExecutionContexts.Last: PExecutionContext;
418begin
419 Result := @ExecutionContexts.Items[Length(ExecutionContexts.Items) - 1];
420end;
421
422procedure TExecutionContexts.Add;
423begin
424 SetLength(Items, Length(Items) + 1);
425 ExecutionContextCurrent := Last;
426end;
427
428procedure TExecutionContexts.RemoveLast;
429begin
430 SetLength(Items, Length(Items) - 1);
431 ExecutionContextCurrent := Last;
432end;
433
434
435end.
436
Note: See TracBrowser for help on using the repository browser.