Ignore:
Timestamp:
Apr 17, 2020, 12:09:15 AM (5 years ago)
Author:
chronos
Message:
  • Added: Support for String, Integer and Boolean types.
  • Added: Support for more system defined functions..
  • Added: Support for line comments.
  • Added: For-To-Do construction.
  • Added: Defined function parameters and and parsing function calls with parameters.
  • Modified: Improved handling of expressions.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/interpreter2/UExecutor.pas

    r201 r202  
    99
    1010type
     11  TExecutorFunctions = class;
     12
    1113  TExecutorVariable = class
    1214    Variable: TVariable;
    13     Value: string;
     15    Value: TValue;
    1416  end;
    1517
     
    2123  end;
    2224
    23   TExecutorFunctionCallback = function(Params: array of string): string of object;
     25  { TExecutorType }
     26
     27  TExecutorType = class
     28    TypeRef: TType;
     29    Functions: TExecutorFunctions;
     30    constructor Create;
     31    destructor Destroy; override;
     32  end;
     33
     34  { TExecutorTypes }
     35
     36  TExecutorTypes = class(TObjectList)
     37    function SearchByType(TypeRef: TType): TExecutorType;
     38    function AddNew(TypeRef: TType): TExecutorType;
     39  end;
     40
     41  TExecutorFunctionCallback = function(Params: array of TValue): TValue of object;
    2442
    2543  TExecutorFunction = class
     
    3957  TExecutorBlock = class
    4058    Parent: TExecutorBlock;
     59    Types: TExecutorTypes;
    4160    Variables: TExecutorVariables;
    4261    Functions: TExecutorFunctions;
    4362    function GetFunction(FunctionDef: TFunction): TExecutorFunction;
     63    function GetType(TypeDef: TType): TExecutorType;
     64    function GetVariable(Variable: TVariable): TExecutorVariable;
     65    function GetTypeFunction(TypeDef: TType; FunctionDef: TFunction): TExecutorFunction; overload;
     66    function GetTypeFunction(TypeDef: TType; FunctionName: string): TExecutorFunction; overload;
    4467    constructor Create;
    4568    destructor Destroy; override;
     
    5477    FOnOutput: TOutputEvent;
    5578    SystemBlock: TExecutorBlock;
    56     function ExecuteWriteLn(Params: array of string): string;
    57     function ExecuteWrite(Params: array of string): string;
     79    function ExecuteWriteLn(Params: array of TValue): TValue;
     80    function ExecuteWrite(Params: array of TValue): TValue;
     81    function ExecuteIntToStr(Params: array of TValue): TValue;
     82    function ExecuteStrToInt(Params: array of TValue): TValue;
     83    function ExecuteStringAssign(Params: array of TValue): TValue;
     84    function ExecuteStringAdd(Params: array of TValue): TValue;
     85    function ExecuteStringEqual(Params: array of TValue): TValue;
     86    function ExecuteStringNotEqual(Params: array of TValue): TValue;
     87    function ExecuteIntegerAssign(Params: array of TValue): TValue;
     88    function ExecuteIntegerAdd(Params: array of TValue): TValue;
     89    function ExecuteIntegerSub(Params: array of TValue): TValue;
     90    function ExecuteIntegerEqual(Params: array of TValue): TValue;
     91    function ExecuteIntegerNotEqual(Params: array of TValue): TValue;
    5892    procedure InitExecutorBlock(ExecutorBlock: TExecutorBlock; Block: TBlock);
    5993  public
     
    6498    procedure ExecuteIfThenElse(Block: TExecutorBlock; IfThenElse: TIfThenElse);
    6599    procedure ExecuteWhileDo(Block: TExecutorBlock; WhileDo: TWhileDo);
     100    procedure ExecuteForToDo(Block: TExecutorBlock; ForToDo: TForToDo);
    66101    procedure ExecuteBlock(ParentBlock: TExecutorBlock;Block: TBlock);
    67     function ExecuteFunctionCall(Block: TExecutorBlock; FunctionCall: TFunctionCall): string;
     102    function ExecuteFunctionCall(Block: TExecutorBlock; FunctionCall: TFunctionCall): TValue;
    68103    procedure ExecuteAssignment(Block: TExecutorBlock; Assignment: TAssignment);
    69     function ExecuteExpression(Block: TExecutorBlock; Expression: TExpression): string;
     104    function ExecuteExpression(Block: TExecutorBlock; Expression: TExpression): TValue;
     105    function ExecuteExpressionOperation(Block: TExecutorBlock; Expression: TExpressionOperation): TValue;
     106    function ExecuteExpressionOperand(Block: TExecutorBlock; Expression: TExpressionOperand): TValue;
    70107    procedure Run;
    71108    procedure Output(Text: string);
     
    75112
    76113implementation
     114
     115{ TExecutorType }
     116
     117constructor TExecutorType.Create;
     118begin
     119  Functions := TExecutorFunctions.Create;
     120end;
     121
     122destructor TExecutorType.Destroy;
     123begin
     124  Functions.Free;
     125  inherited Destroy;
     126end;
     127
     128{ TExecutorTypes }
     129
     130function TExecutorTypes.SearchByType(TypeRef: TType): TExecutorType;
     131var
     132  I: Integer;
     133begin
     134  I := 0;
     135  while (I < Count) and (TExecutorType(Items[I]).TypeRef <> TypeRef) do Inc(I);
     136  if I < Count then Result := TExecutorType(Items[I])
     137    else Result := nil;
     138end;
     139
     140function TExecutorTypes.AddNew(TypeRef: TType): TExecutorType;
     141begin
     142  Result := TExecutorType.Create;
     143  Result.TypeRef := TypeRef;
     144  Add(Result);
     145end;
    77146
    78147{ TExecutorFunctions }
     
    124193end;
    125194
     195function TExecutorBlock.GetType(TypeDef: TType): TExecutorType;
     196begin
     197  Result := Types.SearchByType(TypeDef);
     198  if not Assigned(Result) and Assigned(Parent) then
     199    Result := Parent.GetType(TypeDef);
     200end;
     201
     202function TExecutorBlock.GetVariable(Variable: TVariable): TExecutorVariable;
     203begin
     204  Result := Variables.SearchByVariable(Variable);
     205  if not Assigned(Result) and Assigned(Parent) then
     206    Result := Parent.GetVariable(Variable);
     207end;
     208
     209function TExecutorBlock.GetTypeFunction(TypeDef: TType; FunctionDef: TFunction
     210  ): TExecutorFunction;
     211var
     212  ExecutorType: TExecutorType;
     213begin
     214  ExecutorType := GetType(TypeDef);
     215  Result := ExecutorType.Functions.SearchByFunction(FunctionDef);
     216end;
     217
     218function TExecutorBlock.GetTypeFunction(TypeDef: TType; FunctionName: string
     219  ): TExecutorFunction;
     220begin
     221  Result := GetTypeFunction(TypeDef, TypeDef.Functions.SearchByName(FunctionName));
     222end;
     223
    126224constructor TExecutorBlock.Create;
    127225begin
     226  Types := TExecutorTypes.Create;
    128227  Variables := TExecutorVariables.Create;
    129228  Functions := TExecutorFunctions.Create;
     
    134233  Variables.Free;
    135234  Functions.Free;
     235  Types.Free;
    136236  inherited Destroy;
    137237end;
     
    139239{ TExecutor }
    140240
    141 function TExecutor.ExecuteWriteLn(Params: array of string): string;
     241function TExecutor.ExecuteWriteLn(Params: array of TValue): TValue;
    142242var
    143243  I: Integer;
    144244  Text: string;
    145245begin
    146   Result := '';
     246  Result := nil;
    147247  Text := '';
    148248  for I := 0 to Length(Params) - 1 do
    149     Text := Text + Params[I];
     249    Text := Text + TValueString(Params[I]).Value;
    150250  Output(Text + LineEnding);
    151251end;
    152252
    153 function TExecutor.ExecuteWrite(Params: array of string): string;
     253function TExecutor.ExecuteWrite(Params: array of TValue): TValue;
    154254var
    155255  I: Integer;
    156256  Text: string;
    157257begin
    158   Result := '';
     258  Result := nil;
    159259  Text := '';
    160260  for I := 0 to Length(Params) - 1 do
    161     Text := Text + Params[I];
     261    Text := Text + TValueString(Params[I]).Value;
    162262  Output(Text);
    163263end;
    164264
     265function TExecutor.ExecuteIntToStr(Params: array of TValue): TValue;
     266begin
     267  Result := TValueString.Create;
     268  TValueString(Result).Value := IntToStr(TValueInteger(Params[0]).Value);
     269end;
     270
     271function TExecutor.ExecuteStrToInt(Params: array of TValue): TValue;
     272begin
     273  Result := TValueInteger.Create;
     274  TValueInteger(Result).Value := StrToInt(TValueString(Params[0]).Value);
     275end;
     276
     277function TExecutor.ExecuteStringAssign(Params: array of TValue): TValue;
     278begin
     279  Result := TValueString.Create;
     280  TValueString(Result).Value := TValueString(Params[0]).Value;
     281end;
     282
     283function TExecutor.ExecuteStringAdd(Params: array of TValue): TValue;
     284begin
     285  Result := TValueString.Create;
     286  TValueString(Result).Value := TValueString(Params[0]).Value + TValueString(Params[1]).Value;
     287end;
     288
     289function TExecutor.ExecuteStringEqual(Params: array of TValue): TValue;
     290begin
     291  Result := TValueBoolean.Create;
     292  TValueBoolean(Result).Value := TValueString(Params[0]).Value = TValueString(Params[1]).Value;
     293end;
     294
     295function TExecutor.ExecuteStringNotEqual(Params: array of TValue): TValue;
     296begin
     297  Result := TValueBoolean.Create;
     298  TValueBoolean(Result).Value := TValueString(Params[0]).Value <> TValueString(Params[1]).Value;
     299end;
     300
     301function TExecutor.ExecuteIntegerAssign(Params: array of TValue): TValue;
     302begin
     303  Result := TValueInteger.Create;
     304  TValueInteger(Result).Value := TValueInteger(Params[0]).Value;
     305end;
     306
     307function TExecutor.ExecuteIntegerAdd(Params: array of TValue): TValue;
     308begin
     309  Result := TValueInteger.Create;
     310  TValueInteger(Result).Value := TValueInteger(Params[0]).Value + TValueInteger(Params[1]).Value;
     311end;
     312
     313function TExecutor.ExecuteIntegerSub(Params: array of TValue): TValue;
     314begin
     315  Result := TValueInteger.Create;
     316  TValueInteger(Result).Value := TValueInteger(Params[0]).Value - TValueInteger(Params[1]).Value;
     317end;
     318
     319function TExecutor.ExecuteIntegerEqual(Params: array of TValue): TValue;
     320begin
     321  Result := TValueBoolean.Create;
     322  TValueBoolean(Result).Value := TValueInteger(Params[0]).Value = TValueInteger(Params[1]).Value;
     323end;
     324
     325function TExecutor.ExecuteIntegerNotEqual(Params: array of TValue): TValue;
     326begin
     327  Result := TValueBoolean.Create;
     328  TValueBoolean(Result).Value := TValueInteger(Params[0]).Value <> TValueInteger(Params[1]).Value;
     329end;
     330
    165331procedure TExecutor.InitExecutorBlock(ExecutorBlock: TExecutorBlock; Block: TBlock);
    166332var
    167333  I: Integer;
     334  J: Integer;
    168335  ExecutorFunction: TExecutorFunction;
    169 begin
     336  ExecutorType: TExecutorType;
     337begin
     338  for I := 0 to Block.Types.Count - 1 do begin
     339    ExecutorType := ExecutorBlock.Types.AddNew(TType(Block.Types[I]));
     340    for J := 0 to ExecutorType.TypeRef.Functions.Count - 1 do begin
     341      ExecutorFunction := ExecutorType.Functions.AddNew(TFunction(ExecutorType.TypeRef.Functions[J]));
     342      if ExecutorType.TypeRef.Name = 'string' then begin
     343        if ExecutorFunction.FunctionDef.Name = '_Assign' then begin
     344          ExecutorFunction.Callback := ExecuteStringAssign;
     345        end else
     346        if ExecutorFunction.FunctionDef.Name = '_Add' then begin
     347          ExecutorFunction.Callback := ExecuteStringAdd;
     348        end else
     349        if ExecutorFunction.FunctionDef.Name = '_Equal' then begin
     350          ExecutorFunction.Callback := ExecuteStringEqual;
     351        end;
     352        if ExecutorFunction.FunctionDef.Name = '_NotEqual' then begin
     353          ExecutorFunction.Callback := ExecuteStringNotEqual;
     354        end;
     355      end;
     356      if ExecutorType.TypeRef.Name = 'Integer' then begin
     357        if ExecutorFunction.FunctionDef.Name = '_Assign' then begin
     358          ExecutorFunction.Callback := ExecuteIntegerAssign;
     359        end else
     360        if ExecutorFunction.FunctionDef.Name = '_Add' then begin
     361          ExecutorFunction.Callback := ExecuteIntegerAdd;
     362        end else
     363        if ExecutorFunction.FunctionDef.Name = '_Sub' then begin
     364          ExecutorFunction.Callback := ExecuteIntegerSub;
     365        end else
     366        if ExecutorFunction.FunctionDef.Name = '_Equal' then begin
     367          ExecutorFunction.Callback := ExecuteIntegerEqual;
     368        end else
     369        if ExecutorFunction.FunctionDef.Name = '_NotEqual' then begin
     370          ExecutorFunction.Callback := ExecuteIntegerNotEqual;
     371        end;
     372      end;
     373    end;
     374  end;
    170375  for I := 0 to Block.Variables.Count - 1 do
    171376    ExecutorBlock.Variables.AddNew(TVariable(Block.Variables[I]));
    172377  for I := 0 to Block.Functions.Count - 1 do begin
    173378    ExecutorFunction := ExecutorBlock.Functions.AddNew(TFunction(Block.Functions[I]));
    174     if ExecutorFunction.FunctionDef.Name = 'Write' then ExecutorFunction.Callback := ExecuteWrite
    175     else if ExecutorFunction.FunctionDef.Name = 'WriteLn' then ExecutorFunction.Callback := ExecuteWriteLn;
     379    if ExecutorFunction.FunctionDef.Name = 'Write' then begin
     380      ExecutorFunction.Callback := ExecuteWrite;
     381    end else
     382    if ExecutorFunction.FunctionDef.Name = 'WriteLn' then begin
     383      ExecutorFunction.Callback := ExecuteWriteLn;
     384    end;
     385    if ExecutorFunction.FunctionDef.Name = 'IntToStr' then begin
     386      ExecutorFunction.Callback := ExecuteIntToStr;
     387    end else
     388    if ExecutorFunction.FunctionDef.Name = 'StrToInt' then begin
     389      ExecutorFunction.Callback := ExecuteStrToInt;
     390    end;
    176391  end;
    177392end;
     
    200415  else if Command is TIfThenElse then ExecuteIfThenElse(Block, TIfThenElse(Command))
    201416  else if Command is TWhileDo then ExecuteWhileDo(Block, TWhileDo(Command))
     417  else if Command is TForToDo then ExecuteForToDo(Block, TForToDo(Command))
    202418  else raise Exception.Create('Unsupported command type');
    203419end;
     
    206422  IfThenElse: TIfThenElse);
    207423var
    208   Value: string;
     424  Value: TValue;
    209425begin
    210426  Value := ExecuteExpression(Block, IfThenElse.Expression);
    211   if Value <> '' then ExecuteCommand(Block, IfThenElse.CommandThen)
    212     else ExecuteCommand(Block, IfThenElse.CommandElse);
     427  if Value is TValueBoolean then begin
     428    if TValueBoolean(Value).Value then ExecuteCommand(Block, IfThenElse.CommandThen)
     429      else ExecuteCommand(Block, IfThenElse.CommandElse);
     430  end else raise Exception.Create('Expected boolean value.');
    213431end;
    214432
    215433procedure TExecutor.ExecuteWhileDo(Block: TExecutorBlock; WhileDo: TWhileDo);
    216434var
    217   Value: string;
     435  Value: TValue;
    218436begin
    219437  while True do begin
    220438    Value := ExecuteExpression(Block, WhileDo.Expression);
    221     if Value <> '' then Continue
    222       else Break;
     439    if Value is TValueBoolean then begin
     440      if not TValueBoolean(Value).Value then Break;
     441      ExecuteCommand(Block, WhileDo.Command);
     442    end else raise Exception.Create('Expected boolean value.');
     443  end;
     444end;
     445
     446procedure TExecutor.ExecuteForToDo(Block: TExecutorBlock; ForToDo: TForToDo);
     447var
     448  Value: TValue;
     449  Variable: TExecutorVariable;
     450  Limit: TValue;
     451begin
     452  Variable := Block.GetVariable(ForToDo.VariableRef);
     453  Variable.Value := ExecuteExpression(Block, ForToDo.ExpressionFrom);
     454  Limit := ExecuteExpression(Block, ForToDo.ExpressionTo);
     455  while True do begin
     456    ExecuteCommand(Block, ForToDo.Command);
     457    TValueInteger(Variable.Value).Value := TValueInteger(Variable.Value).Value + 1;
     458    if TValueInteger(Variable.Value).Value > TValueInteger(Limit).Value then Break;
    223459  end;
    224460end;
     
    236472
    237473function TExecutor.ExecuteFunctionCall(Block: TExecutorBlock;
    238   FunctionCall: TFunctionCall): string;
     474  FunctionCall: TFunctionCall): TValue;
    239475var
    240476  ExecutorFunction: TExecutorFunction;
    241   Params: array of string;
    242   I: Integer;
    243 begin
    244   Result := '';
     477  Params: array of TValue;
     478  I: Integer;
     479begin
     480  Result := nil;
    245481  ExecutorFunction := Block.GetFunction(FunctionCall.FunctionDef);
    246482  if Assigned(ExecutorFunction) then begin
    247483    SetLength(Params, FunctionCall.Params.Count);
    248     for I := 0 to FunctionCall.Params.Count - 1 do
     484    for I := 0 to FunctionCall.Params.Count - 1 do begin
    249485      Params[I] := ExecuteExpression(Block, TExpression(FunctionCall.Params[0]));
     486    end;
    250487    Result := ExecutorFunction.Callback(Params);
    251488  end else raise Exception.Create('No executor for ' + FunctionCall.FunctionDef.Name + ' function.');
     
    255492  Assignment: TAssignment);
    256493var
    257   Value: string;
     494  Value: TValue;
    258495  Variable: TExecutorVariable;
     496  ExecutorFunction: TExecutorFunction;
     497  Params: array of TValue;
    259498begin
    260499  Value := ExecuteExpression(Block, Assignment.Expression);
    261   Variable := Block.Variables.SearchByVariable(Assignment.Variable);
    262   Variable.Value := Value;
     500  Variable := Block.GetVariable(Assignment.Variable);
     501  ExecutorFunction := Block.GetTypeFunction(Assignment.Variable.TypeRef, '_Assign');
     502  if Assignment.Variable.TypeRef = Assignment.Expression.GetType then begin;
     503    SetLength(Params, 1);
     504    Params[0] := Value;
     505    Variable.Value := ExecutorFunction.Callback(Params);
     506  end else raise Exception('Assignment result type is ' + Variable.Variable.TypeRef.Name +
     507    ' but value is ' + Assignment.Expression.GetType.Name + '.');
    263508end;
    264509
    265510function TExecutor.ExecuteExpression(Block: TExecutorBlock;
    266   Expression: TExpression): string;
     511  Expression: TExpression): TValue;
     512begin
     513  if Expression is TExpressionOperation then
     514    Result := ExecuteExpressionOperation(Block, TExpressionOperation(Expression))
     515  else
     516  if Expression is TExpressionOperand then
     517    Result := ExecuteExpressionOperand(Block, TExpressionOperand(Expression))
     518  else raise Exception.Create('Unknown expression class.');
     519end;
     520
     521function TExecutor.ExecuteExpressionOperation(Block: TExecutorBlock;
     522  Expression: TExpressionOperation): TValue;
     523var
     524  I: Integer;
     525  Value: TValue;
     526  ExecutorFunction: TExecutorFunction;
     527  Params: array of TValue;
     528  FuncName: string;
     529begin
     530  if Expression.Operation = eoAdd then FuncName := '_Add'
     531  else if Expression.Operation = eoSub then FuncName := '_Sub'
     532  else if Expression.Operation = eoEqual then FuncName := '_Equal'
     533  else if Expression.Operation = eoNotEqual then FuncName := '_NotEqual'
     534  else raise Exception.Create('Unsupported operation type.');
     535
     536  ExecutorFunction := Block.GetTypeFunction(Expression.TypeRef, FuncName);
     537  Result := Expression.TypeRef.ValueClass.Create;
     538
     539  SetLength(Params, Expression.Items.Count);
     540  for I := 0 to Expression.Items.Count - 1 do begin
     541    Value := ExecuteExpression(Block, TExpression(Expression.Items[I]));
     542    Params[I] := Value;
     543  end;
     544  Result := ExecutorFunction.Callback(Params);
     545end;
     546
     547function TExecutor.ExecuteExpressionOperand(Block: TExecutorBlock;
     548  Expression: TExpressionOperand): TValue;
    267549begin
    268550  if Assigned(Expression.VariableRef) then begin
     
    274556  if Assigned(Expression.FunctionCall) then begin
    275557    Result := ExecuteFunctionCall(Block, Expression.FunctionCall);
    276   end;
     558  end else raise Exception.Create('Unsupported exception operand type.');
    277559end;
    278560
Note: See TracChangeset for help on using the changeset viewer.