Lucrarea nr. 6
 Siruri de caractere






Exista doua tipuri utilizate pentru reprezentarea sirurilor de caractere. Prima forma de reprezentare o constituie tipul atom ('ca acesta'). Dezavantajul utilizarii acestui tip este faptul ca atomii ocupa spatiu in tabela de simboluri, existand anumite limite la numarul si dimensiunea acestora. In Prolog-uri stil Edinburgh (ca SWI-Prolog), exista definit tipul string reprezentat ca o lista de coduri numerice. De exemplu:

    "abc" = [97,98,99]
sau
    "abc" = [0'a,0'b,0'c]

Lipsa unui standard uniform acceptat de siruri induce faptul ca predicatele ce opereaza asupra acestui tip sunt putine si nestandard. Exista doua predicate de conversie bidirectionala intre string si atom, respectiv numar:

    atom_chars(ab,"ab").
    number_chars(45,"45e+1").

Acest deficit legat de predicate nu este insa un dezavantaj semnificativ pentru ca sirurile pot fi tratate ca si liste. De exemplu concatenarea a doua siruri este identica cu concatenarea a doua liste:

    append("ab", "cd", "abcd") /* append este un predicat predefinit in SWI PROLOG */

O aplicatie naturala pentru siruri de caractere o reprezinta analizoarele sintactice. In Prolog este foarte naturala implementarea unui analizor sintactic descendent, neterminalele transfomindu-se in predicate. In fisierul "as.pl" este data o posibila implementare pentru gramatica de mai jos:

    -> compound_instr.
    compound_instr -> BEGIN instr_list END
    instr_list     -> instr; instr_list
                    | instr
    instr          -> compound_instr
                    | assignment
                    | if_then_else
                    | nil
    assignment     -> IDENT := expr
    if_then_else   -> IF expr THEN instr ELSE instr
    expr           -> expr [+-] termen | termen
    termen         -> NUMAR | IDENT | (expr)

Regula gramaticala pentru expresie este recursiva la stanga, ceea ce provoaca un ciclu infinit pentru o expresie gresita sintactic. Prin factorizare se obtine gramatica echivalenta:

    expr   ->  termen expr1
    expr1  ->  [+-] termen expr1 | nil

Probleme:

  1. Sa se expandeze gramatica expresiilor pentru operatorii *, /, = si <>. In acest caz gramatica expresiilor va avea forma

  2.     expr   -> exprs [='<>'] exprs | exprs
        exprs  -> exprs [+-] termen | termen
        termen -> termen [*/] factor | factor
        factor -> NUMAR | IDENT | (exprs)
     
  3.  Sa se construiasca arborele sintactic pentru programul dat ca argument. Functorii sugerati pentru noduri sint:

  4.     compound_instr( [Instr, .. , Instr] )
        instr(Compound_instr); instr(Assignment); instr(If_Then_Else)
        assign(LeftId, RightExpr)
        if(Cond, Then, Else)
        +(Termen, Expr); -(Termen, Expr)

                De exemplu pentru constructia if-then-else, predicatul se modifica in urmatorul sens:

        if_then_else_tree(Tokens,RestTokens, if(Cond,Then,Else)) :-
            Tokens = ["if" | T1],
            expr_tree(T1,T2, Cond),
            T2 = ["then"|T3],
            instr_tree(T3,T4, Then),
            T4 = ["else" | T5],
            instr_tree(T5,RestTokens, Else).
     

  5. Sa se rescrie predicatul fronttoken astfel incat sa permita spargerea in tokenuri fara sa fie necesar un spatiu dupa fiecare token. De exemplu, sirul "a:=1+2;" ar contine 6 simboluri lexicale (respectiv 'a' ':=', '1', '+', '2'si  ';'.).


Pentru cei care au instalat SWI-Prolog: Daca o intrebare pusa la prompterul Prologului contine siruri intre "", atunci nu functioneaza mecanismul de history. Pentru a rezolva aceasta problema trebuie modificat predicatul 'emacs_insert_command' din fisierul ".../pl-2.9.5/library/emacs_interface.pl":

    kl_atom(A,A1) :- atom_chars(A,S), kl_string(S,S1), atom_chars(A1,S1).
    kl_string([],[]).
    kl_string([34|S],[92,34|S1]) :- !, kl_string(S,S1). /* \" */
    kl_string([92|S],[92,92|S1]) :- !, kl_string(S,S1). /* \\ */
    kl_string([H|S],[H|S1]) :- kl_string(S,S1).

    emacs_insert_command(Nr) :-
        recorded('$history_list', Nr/Command_kl), !,
        kl_atom(Command_kl,Command),
        flag(emacs_shown_command, _, Nr),
        call_emacs('(prolog-insert-history-command "~w")', Command).
    emacs_insert_command(_) :-
        call_emacs('(prolog-completion-error-message "No more commands")').