Ignore:
Timestamp:
Jan 17, 2018, 3:34:13 PM (7 years ago)
Author:
chronos
Message:
  • Added: Support for Repeat blocks and Break command.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/easy compiler/USourceExecutor.pas

    r146 r147  
    2222  TExecutorVariables = class(TObjectList)
    2323    function Search(Variable: TSourceVariable): TExecutorVariable;
     24  end;
     25
     26  TExecutorRepeat = class
     27    RepeatCommand: TCommandRepeat;
     28    Terminated: Boolean;
     29  end;
     30
     31  { TExecutorRepeats }
     32
     33  TExecutorRepeats = class(TObjectList)
     34    function Search(RepeatCommand: TCommandRepeat): TExecutorRepeat;
    2435  end;
    2536
     
    3142    FOnOutput: TOutputEvent;
    3243    Variables: TExecutorVariables;
     44    RepeatBlocks: TExecutorRepeats;
     45    SkipNext: Boolean;
    3346    procedure ExecuteBeginEnd(BeginEnd: TCommandBeginEnd);
     47    procedure ExecuteCommand(Command: TSourceCommand);
     48    procedure ExecuteBreak(CommandBreak: TCommandBreak);
     49    procedure ExecuteRepeat(CommandRepeat: TCommandRepeat);
     50    function ReadValueReference(Reference: TSourceReference): TSourceValue;
     51    function ReadVarReference(Reference: TSourceReference): TSourceVariable;
    3452  public
    3553    constructor Create;
     
    4361implementation
    4462
     63{ TExecutorRepeat }
     64
     65function TExecutorRepeats.Search(RepeatCommand: TCommandRepeat): TExecutorRepeat;
     66var
     67  Item: TExecutorRepeat;
     68begin
     69  Result := nil;
     70  for Item in Self do
     71  if Item.RepeatCommand = RepeatCommand then begin
     72    Result := Item;
     73    Break;
     74  end;
     75end;
     76
    4577{ TExecutorVariable }
    4678
     
    71103begin
    72104  Variables := TExecutorVariables.Create;
     105  RepeatBlocks := TExecutorRepeats.Create;
    73106end;
    74107
    75108destructor TSourceExecutor.Destroy;
    76109begin
     110  RepeatBlocks.Free;
    77111  Variables.Free;
    78112  inherited Destroy;
     
    81115procedure TSourceExecutor.Execute(SourceCode: TSourceCode);
    82116begin
     117  SkipNext := False;
    83118  ExecuteBeginEnd(SourceCode.Main);
    84119end;
    85120
     121function TSourceExecutor.ReadValueReference(Reference: TSourceReference): TSourceValue;
     122begin
     123  Result := nil;
     124  if Reference is TSourceReferenceConstant then begin
     125    Result := TSourceReferenceConstant(Reference).Constant.Value;
     126  end else
     127  if Reference is TSourceReferenceVariable then begin
     128    Result := Variables.Search(TSourceReferenceVariable(Reference).Variable).Value;
     129  end else raise Exception.Create('Unsupported reference');
     130end;
     131
     132function TSourceExecutor.ReadVarReference(Reference: TSourceReference): TSourceVariable;
     133begin
     134  Result := nil;
     135  if Reference is TSourceReferenceVariable then begin
     136    Result := TSourceReferenceVariable(Reference).Variable;
     137  end else raise Exception.Create('Unsupported reference');
     138end;
     139
    86140procedure TSourceExecutor.ExecuteBeginEnd(BeginEnd: TCommandBeginEnd);
    87141var
    88142  IP: Integer;
    89   Instruction: TSourceCommand;
     143begin
     144  IP := 0;
     145  while IP < BeginEnd.Commands.Count do begin
     146    if SkipNext then begin
     147      SkipNext := False;
     148      Inc(IP);
     149      Continue;
     150    end;
     151    ExecuteCommand(TSourceCommand(BeginEnd.Commands[IP]));
     152    Inc(IP);
     153  end;
     154end;
     155
     156procedure TSourceExecutor.ExecuteBreak(CommandBreak: TCommandBreak);
     157var
     158  RepeatBlock: TSourceCommand;
     159  ExecutorRepeat: TExecutorRepeat;
     160begin
     161  RepeatBlock := CommandBreak.Parent;
     162  while not (RepeatBlock is TCommandRepeat) and (RepeatBlock <> nil) do
     163    RepeatBlock := RepeatBlock.Parent;
     164  if Assigned(RepeatBlock) then begin
     165    ExecutorRepeat := RepeatBlocks.Search(RepeatBlock as TCommandRepeat);
     166    if Assigned(ExecutorRepeat) then begin
     167      ExecutorRepeat.Terminated := True;
     168    end else
     169    raise Exception.Create('Missing executor repeat block');
     170  end else
     171  raise Exception.Create('Used break outside repeat loop');
     172end;
     173
     174procedure TSourceExecutor.ExecuteRepeat(CommandRepeat: TCommandRepeat);
     175var
     176  RepeatBlock: TExecutorRepeat;
     177begin
     178  RepeatBlock := TExecutorRepeat.Create;
     179  RepeatBlock.RepeatCommand := CommandRepeat;
     180  RepeatBlock.Terminated := False;
     181  RepeatBlocks.Add(RepeatBlock);
     182  repeat
     183    ExecuteCommand(CommandRepeat.Command);
     184  until RepeatBlock.Terminated;
     185  RepeatBlocks.Remove(RepeatBlock);
     186end;
     187
     188procedure TSourceExecutor.ExecuteCommand(Command: TSourceCommand);
     189var
    90190  Variable: TSourceVariable;
    91191  Value: TSourceValue;
     
    93193  Text: string;
    94194  IntValue: Integer;
    95   SkipNext: Boolean;
    96 
    97 function ReadValueReference(Reference: TSourceReference): TSourceValue;
    98 begin
    99   Result := nil;
    100   if Reference is TSourceReferenceConstant then begin
    101     Result := TSourceReferenceConstant(Reference).Constant.Value;
    102   end else
    103   if Reference is TSourceReferenceVariable then begin
    104     Result := Variables.Search(TSourceReferenceVariable(Reference).Variable).Value;
    105   end else raise Exception.Create('Unsupported reference');
    106 end;
    107 
    108 function ReadVarReference(Reference: TSourceReference): TSourceVariable;
    109 begin
    110   Result := nil;
    111   if Reference is TSourceReferenceVariable then begin
    112     Result := TSourceReferenceVariable(Reference).Variable;
    113   end else raise Exception.Create('Unsupported reference');
    114 end;
    115 
    116 begin
    117   SkipNext := False;
    118   IP := 0;
    119   while IP < BeginEnd.Instructions.Count do begin
    120     if SkipNext then begin
    121       SkipNext := False;
    122       Inc(IP);
    123       Continue;
    124     end;
    125     Instruction := TSourceCommand(BeginEnd.Instructions[IP]);
    126     if Instruction is TCommandFunctionCall then
    127     with TCommandFunctionCall(Instruction) do begin
    128       if Name = 'print' then begin
    129         if Assigned(FOnOutput) then begin
    130           Value := ReadValueReference(TSourceReference(Parameters[0]));
    131           if Value is TSourceValueString then
    132             FOnOutput(TSourceValueString(Value).Value)
    133           else if Value is TSourceValueInteger then
    134             FOnOutput(IntToStr(TSourceValueInteger(Value).Value))
    135           else raise Exception.Create('Unsupported value type');
    136         end;
     195begin
     196  if Command is TCommandFunctionCall then
     197  with TCommandFunctionCall(Command) do begin
     198    if Name = 'print' then begin
     199      if Assigned(FOnOutput) then begin
     200        Value := ReadValueReference(TSourceReference(Parameters[0]));
     201        if Value is TSourceValueString then
     202          FOnOutput(TSourceValueString(Value).Value)
     203        else if Value is TSourceValueInteger then
     204          FOnOutput(IntToStr(TSourceValueInteger(Value).Value))
     205        else raise Exception.Create('Unsupported value type');
     206      end;
     207    end else
     208    if Name = 'println' then begin
     209      if Assigned(FOnOutput) then begin
     210        Value := ReadValueReference(TSourceReference(Parameters[0]));
     211        if Value is TSourceValueString then
     212          FOnOutput(TSourceValueString(Value).Value + LineEnding)
     213        else if Value is TSourceValueInteger then
     214          FOnOutput(IntToStr(TSourceValueInteger(Value).Value) + LineEnding)
     215        else raise Exception.Create('Unsupported value type');
     216      end;
     217    end else
     218    if Name = 'inputln' then begin
     219      if Assigned(FOnInput) then begin
     220        Variable := ReadVarReference(TSourceReference(Parameters[0]));
     221        ExecutorVar := Variables.Search(Variable);
     222        if ExecutorVar.Value is TSourceValueString then begin
     223          TSourceValueString(ExecutorVar.Value).Value := FOnInput;
     224          FOnOutput(TSourceValueString(ExecutorVar.Value).Value + LineEnding);
     225        end else
     226        if ExecutorVar.Value is TSourceValueInteger then begin
     227          Text := FOnInput;
     228          if TryStrToInt(Text, IntValue) then
     229            TSourceValueInteger(ExecutorVar.Value).Value := IntValue
     230            else TSourceValueInteger(ExecutorVar.Value).Value := 0;
     231          FOnOutput(IntToStr(TSourceValueInteger(ExecutorVar.Value).Value) + LineEnding);
     232        end else
     233        raise Exception.Create('Unsupported value type');
     234      end;
     235    end else
     236    if Name = 'assign' then begin
     237      Variable := ReadVarReference(TSourceReference(Parameters[0]));
     238      Value := ReadValueReference(TSourceReference(Parameters[1]));
     239      ExecutorVar := Variables.Search(Variable);
     240      if not Assigned(ExecutorVar) then begin
     241        ExecutorVar := TExecutorVariable.Create;
     242        ExecutorVar.Variable := Variable;
     243        Variables.Add(ExecutorVar);
     244        ExecutorVar.Value := Variable.ValueType.ValueClass.Create;
     245      end;
     246      ExecutorVar.Value.Assign(Value);
     247    end else
     248    if Name = 'increment' then begin
     249      Variable := ReadVarReference(TSourceReference(Parameters[0]));
     250      Value := ReadValueReference(TSourceReference(Parameters[1]));
     251      ExecutorVar := Variables.Search(Variable);
     252      if not Assigned(ExecutorVar) then raise Exception.Create('Variable not found');
     253      if (ExecutorVar.Value is TSourceValueInteger) and (Value is TSourceValueInteger) then
     254        Inc(TSourceValueInteger(ExecutorVar.Value).Value, TSourceValueInteger(Value).Value)
     255      else raise Exception.Create('Wrong type for increment');
     256    end else
     257    if Name = 'decrement' then begin
     258      Variable := ReadVarReference(TSourceReference(Parameters[0]));
     259      Value := ReadValueReference(TSourceReference(Parameters[1]));
     260      ExecutorVar := Variables.Search(Variable);
     261      if not Assigned(ExecutorVar) then raise Exception.Create('Variable not found');
     262      if (ExecutorVar.Value is TSourceValueInteger) and (Value is TSourceValueInteger) then
     263        Dec(TSourceValueInteger(ExecutorVar.Value).Value, TSourceValueInteger(Value).Value)
     264      else raise Exception.Create('Wrong type for increment');
     265    end else
     266    raise Exception.Create('Unsupported function: ' + TCommandFunctionCall(Command).Name);
     267  end else
     268  if Command is TCommandBeginEnd then begin
     269    ExecuteBeginEnd(TCommandBeginEnd(Command));
     270  end else
     271  if Command is TCommandBreak then begin
     272    ExecuteBreak(TCommandBreak(Command));
     273  end else
     274  if Command is TCommandIfZero then begin
     275    ExecutorVar := Variables.Search(TCommandIfZero(Command).Variable.Variable);
     276    if Assigned(ExecutorVar) then begin
     277      if ExecutorVar.Variable.ValueType.Name = 'Integer' then begin
     278        if TSourceValueInteger(ExecutorVar.Value).Value <> 0 then SkipNext := True;
    137279      end else
    138       if Name = 'println' then begin
    139         if Assigned(FOnOutput) then begin
    140           Value := ReadValueReference(TSourceReference(Parameters[0]));
    141           if Value is TSourceValueString then
    142             FOnOutput(TSourceValueString(Value).Value + LineEnding)
    143           else if Value is TSourceValueInteger then
    144             FOnOutput(IntToStr(TSourceValueInteger(Value).Value) + LineEnding)
    145           else raise Exception.Create('Unsupported value type');
    146         end;
    147       end else
    148       if Name = 'inputln' then begin
    149         if Assigned(FOnInput) then begin
    150           Variable := ReadVarReference(TSourceReference(Parameters[0]));
    151           ExecutorVar := Variables.Search(Variable);
    152           if ExecutorVar.Value is TSourceValueString then begin
    153             TSourceValueString(ExecutorVar.Value).Value := FOnInput;
    154             FOnOutput(TSourceValueString(ExecutorVar.Value).Value + LineEnding);
    155           end else
    156           if ExecutorVar.Value is TSourceValueInteger then begin
    157             Text := FOnInput;
    158             if TryStrToInt(Text, IntValue) then
    159               TSourceValueInteger(ExecutorVar.Value).Value := IntValue
    160               else TSourceValueInteger(ExecutorVar.Value).Value := 0;
    161             FOnOutput(IntToStr(TSourceValueInteger(ExecutorVar.Value).Value) + LineEnding);
    162           end else
    163           raise Exception.Create('Unsupported value type');
    164         end;
    165       end else
    166       if Name = 'assign' then begin
    167         Variable := ReadVarReference(TSourceReference(Parameters[0]));
    168         Value := ReadValueReference(TSourceReference(Parameters[1]));
    169         ExecutorVar := Variables.Search(Variable);
    170         if not Assigned(ExecutorVar) then begin
    171           ExecutorVar := TExecutorVariable.Create;
    172           ExecutorVar.Variable := Variable;
    173           Variables.Add(ExecutorVar);
    174           ExecutorVar.Value := Variable.ValueType.ValueClass.Create;
    175         end;
    176         ExecutorVar.Value.Assign(Value);
    177       end else
    178       if Name = 'increment' then begin
    179         Variable := ReadVarReference(TSourceReference(Parameters[0]));
    180         Value := ReadValueReference(TSourceReference(Parameters[1]));
    181         ExecutorVar := Variables.Search(Variable);
    182         if not Assigned(ExecutorVar) then raise Exception.Create('Variable not found');
    183         if (ExecutorVar.Value is TSourceValueInteger) and (Value is TSourceValueInteger) then
    184           Inc(TSourceValueInteger(ExecutorVar.Value).Value, TSourceValueInteger(Value).Value)
    185         else raise Exception.Create('Wrong type for increment');
    186       end else
    187       raise Exception.Create('Unsupported function: ' + TCommandFunctionCall(Instruction).Name);
    188     end else
    189     if Instruction is TCommandBeginEnd then begin
    190       ExecuteBeginEnd(TCommandBeginEnd(Instruction));
    191     end else
    192     if Instruction is TCommandIfZero then begin
    193       ExecutorVar := Variables.Search(TCommandIfZero(Instruction).Variable);
    194       if Assigned(ExecutorVar) then begin
    195         if ExecutorVar.Variable.ValueType.Name = 'Integer' then begin
    196           if TSourceValueInteger(ExecutorVar.Value).Value = 0 then SkipNext := True;
    197         end else
    198         raise Exception.Create('Can compare only integers');
    199       end else
    200       raise Exception.Create('Variable not found');
    201     end else
    202     raise Exception.Create('Unsupported instruction');
    203     Inc(IP);
    204   end;
     280      raise Exception.Create('Can compare only integers');
     281    end else
     282    raise Exception.Create('Variable not found');
     283  end else
     284  if Command is TCommandRepeat then begin
     285    ExecuteRepeat(Command as TCommandRepeat);
     286  end else
     287  raise Exception.Create('Unsupported instruction');
    205288end;
    206289
Note: See TracChangeset for help on using the changeset viewer.