(* Se considera siruri finite de caractere formate din parantezele (, ), [, ], {, }.
   Un sir se este corect numai atunci cand el poate fi construit cu ajutorul urmatoarelor reguli:
   a) sirul vid este corect;
   b) daca A este un sir corect, atunci (A), [A] si {A} sunt siruri corecte;
   c) daca A si B sunt siruri corecte, atunci AB este un sir corect. *)

Program Tema_2_5_Probl_5;
uses crt;

const npar = 3;
      par: array[1..npar] of string[2] = ('()', '[]', '{}');

var sir: string;    {Sirul de testat}
    error: record   {Descrierea erorii aparute}
       msg: string;
       poz: word;
       c:   char;
    end;

function CorectExpr(sir: String): Boolean; {Functia care verifica corectitudinea sirului}
type Stiva = ^Celula; {Adresa unei celule}
     Celula = record  {O celula}
       Info: Char;    {Continutul celulei}
       Prec: Stiva;   {Adresa celulei precedente}
     end;
var S, R: Stiva;   {S - stiva; R - variabila auxiliara}
    l, i: word;
begin
  S := nil;        {Initial stiva este vida}
  l := 0;          {Variabila contor pentru parcurgerea sirului}
  error.msg := ''; {Initial nu este nici o eroare}
  while l < Length(sir) do
  begin
    inc(l);
    for i := 1 to npar do  {Parcurgem lista de paranteze}
      if sir[l] = par[i][1] then {Deskiderea parantezei}
        begin (*  '(', '[', '{'  *)
          New(R);            {Alocarea memoriei pentru elementul nou}
          R^.Info := sir[l]; {Simbolul parantezei de deskidere}
          R^.Prec := S;      {Adresa elementului precedent din stiva}
          S := R;            {Actualizarea adresei stivei}
          Break;             {Intreruperea ciclului for, simbolul parantezei a fost gasit}
        end else
      if sir[l] = par[i][2] then {Inkiderea parantezei}
        begin (*  ')', ']', '}'  *)
          if (S=nil) or (S^.Info<>par[i][1]) then {Eroare sintactica}
            with error do begin
               poz := l;
               c   := sir[l];
               if (S=nil) then  msg := 'Paranteza nu a fost deschisa'
                          else  msg := 'Paranteza nu este inchisa corect';
               CorectExpr := false;
               Exit;  {Se intrerupe executia functiei in caz de eroare}
            end;
          R := S;            {Obtinerea elementului din stiva}
          S := S^.Prec;      {Eliminarea ultimului element din stiva}
          Dispose(R);        {Eliberarea memoriei}
          Break;             {Intreruperea ciclului for, simbolul parantezei a fost gasit}
        end else {Simbolul sir[l] nu reprezinta o paranteza};
  end;
  
  if S <> nil then {Daca stiva nu este vida, sirul nu este corect}
    with error do begin
      poz := l;
      c   := S^.Info;
      msg := 'Nu a fost inchisa paranteza';
    end;
    
  CorectExpr := S = nil;
end;

begin
  clrscr;
  writeln('Scrie un sir cu paranteze: ');
  readln(sir);

  Writeln;
  Write('Expresia este ');
  if CorectExpr(sir) then writeln('corecta! :-)')
                     else writeln('incorecta! :-(');
  with error do if msg <> '' then begin
    writeln;
    writeln('Error: ', msg);
    writeln('Poz: ', poz);
    writeln('Char: ', c);
  end;

  readkey;
end.
