Interpréteur

Le patron de conception interpréteur (interpreter) est utilisé pour des logiciels ayant besoin d’un langage (interprète) pour décrire les opérations qu’ils peuvent réaliser.

Quand l’utiliser ?

L’interpréteur est utiliser généralement pour analyser une chaîne algébrique. Le logiciel exécute ensuite des opérations par rapport à cette expression.

Exemple

Nous allons dans cet exemple interpréter une chaîne en notation polonaise inversée. Dans cette notation les opérandes sont présentés avant les opérateurs.

Une liste TStack (fifo) est utilisée, la liste est ensuite dépilée en fonction des types.

Tout d’abord la création d’une interface pour interpréter une expression :

type
  IExpression = interface
  ['{A494FE52-9BA8-4740-9A88-6767706B0C01}']
    procedure Interpret(aStack: TStack);
  end;

Ensuite, la création du premier type, utilisé pour gérer les chiffres, supportant l’interface précédente :

  TTerminalExpression_Number = class(TInterfacedObject, IExpression)
  strict private
    FNumber: integer;
  public
    constructor Create(aNumber: integer);
    procedure Interpret(aStack: TStack);
  end;
 
{ TTerminalExpression_Number }
 
constructor TTerminalExpression_Number.Create(aNumber: integer);
begin
  inherited Create;
  FNumber := aNumber;
end;
 
procedure TTerminalExpression_Number.Interpret(aStack: TStack);
begin
  aStack.Push(FNumber);
end;

Continuons avec l’ajout des types pour les opérandes, il y a deux cas possible, une addition et une soustraction. Les opérations sont réalisées sur les deux dernier élément de la liste.

  TTerminalExpression_Plus = class(TInterfacedObject, IExpression)
  public
    procedure Interpret(aStack: TStack);
  end;
 
  TTerminalExpression_Minus = class(TInterfacedObject, IExpression)
  public
    procedure Interpret(aStack: TStack);
  end;
 
{ TTerminalExpression_Plus }
 
procedure TTerminalExpression_Plus.Interpret(aStack: TStack);
begin
  aStack.Push(aStack.Pop + aStack.Pop);
end;
 
{ TTerminalExpression_Minus }
 
procedure TTerminalExpression_Minus.Interpret(aStack: TStack);
begin
  aStack.Push(- aStack.Pop + aStack.Pop);
end;

Vient ensuite la création de l’analyseur syntaxique (parser) qui va évaluer l’expression et donner le résultat. La TStringList permet de découper la chaîne au niveau des espaces.

  TParser = class
  strict private
    FList: TInterfaceList;
  public
    constructor Create(aString: string);
    function Evaluate: integer;
  end;
 
{ TParser }
 
constructor TParser.Create(aString: string);
var
  ListValue: TStringList;
  i: integer;
begin
  inherited Create;
 
  FList := TInterfaceList.Create;
  ListValue := TStringList.Create;
  try
    ListValue.DelimitedText := aString;
 
    for i := 0 to ListValue.Count - 1 do
    begin
      if ListValue[i] = '+' then
      begin
        FList.Add(TTerminalExpression_Plus.Create);
      end 
      else
      begin
        if ListValue[i] = '-' then
        begin
          FList.Add(TTerminalExpression_Minus.Create);
        end 
        else
        begin
          FList.Add(TTerminalExpression_Number.Create(StrToInt(ListValue[i])));
        end;
      end;
    end;
  finally
    ListValue.Free;
  end;
end;
 
function TParser.Evaluate: integer;
var
  Context: TStack;
  Expression: IInterface;
begin
  Context := TStack.Create;
 
  try
    for Expression in FList do
    begin
      (Expression as IExpression).Interpret(Context);
    end;
 
    Result := Context.Pop;
  finally
    Context.Free;
  end;
end;

Pour finir, il suffit de passer une expression au TParser pour obtenir le résultat (ici le résultat est 20) :

var
  Parser: TParser;
  Value: string;
begin
  try
    Value  := '22 1 3 - +';
    Parser := TParser.Create(Value);
    try
      Writeln(Value, ' = ', Parser.Evaluate);
    finally
      Parser.Free;
    end;
 
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*