
% Tento soubor se sklada z nasledujicich casti:
% 1. - predikaty pro snazsi zadavani vyrazu 
% 2. - pravidla spolecne vsem gramatikam
% 3. - levorekurzivni cyklici gramatika
% 4. - opravena gramatika (s vyuzitim seznamu mezivysledku)
% 5. - gramatika pracujici na reversu vstupu
% 6. - chybna gramatika z manualu sicstu

% =====================================================
% 1. predikaty pro snazsi zadavani vyrazu
% =====================================================
% cti(X) nacte z klavesnice seznam znaku (tj. ASCII kodu)
% vstup se ukonci zmacknutim entru, mezery se ignoruji

cti(X) :- get_code(Code), cti_aux(Code,X).

cti_aux(10,[]) :- !. 	  % zmacknut enter => konec nacitani
cti_aux(32,X) :- cti(X).  % mezera (ignoruje se)
cti_aux(Code,[Code|X]) :- cti(X).

% -----------------------------------------------------
% run nacte vyraz, zavola jeho vyhodnoceni a nakonec odradkuje

run :- write('Napis vyraz nebo rovnici: '), 
       cti(X),
       vyhodnot(X),
       nl.

% -----------------------------------------------------
% vyhodnot(Z) pozna, zda Z je vyraz ci rovnice a 
% podle toho vypise bud hodnotu, nebo zkouma platnost rovnice
% (vyuziva gramatiky definovane v casti 4 - lze lehce zmenit)

vyhodnot(Z) :- vyraz(X,Z,[]), % pouziva cast 4
               % pouziti casti 5: otoc(Z,W), vyraz2(X,W,[]),
               write('Hodnota vyrazu je: '), 
               write(X).
vyhodnot(Z) :- rovnice(X,Y,Z,[]), % pouziva cast 4
               % pouziti casti 5: otoc(Z,W), rovnice2(X,Y,W,[]),
               X =:= Y,
               write('Rovnice plati.').
vyhodnot(Z) :- rovnice(X,Y,Z,[]), % pouziva cast 4
               % pouziti casti 5: otoc(Z,W), rovnice2(X,Y,W,[]),
               X =\= Y,
               write('Rovnice neplati.'),nl,
               write('Hodnota leve strany: '),
               write(X),nl, 
               write('Hodnota prave strany: '),
               write(Y).
                                
% =====================================================
% 2. - pravidla spolecne vsem gramatikam
% =====================================================
% cislice(X) rozpozna cislici a zjisti jeji hodnotu
% odectenim ASCII hodnota nuly od ASCII hodnoty cislice

cislice(X) --> [C],{"0"=<C, C=<"9", X is C - "0"}.

% =====================================================
% 3. - levorekurzivni cyklici gramatika (byla na cvicenich)
% =====================================================
% nefunguje, protoze ma levorekurzivni pravidla pro vyraz_cykli
% a pro cislo_cykli (pokud si tyto pravidla prepisete do klauzuli,
% snadno uvidite duvod cykleni)

vyraz_cykli(Z) --> vyraz_cykli(X),"+",cislo_cykli(Y),{Z is X + Y}.
vyraz_cykli(Z) --> vyraz_cykli(X),"-",cislo_cykli(Y),{Z is X - Y}.
vyraz_cykli(Z) --> cislo_cykli(Z).

cislo_cykli(Z) --> cislo_cykli(X),cislice(Y),{Z is (10 * X) + Y}.
cislo_cykli(Z) --> cislice(Z).

% =====================================================
% 4. - opravena gramatika (s vyuzitim seznamu mezivysledku)
% =====================================================
% jednotlive scitance se ulozi do seznamu (podvyrazy zacinajici 
% minusem chapeme jako zaporne scitance), ten se pak secte pomoci
% predikatu secti
% gramatika dovoluje pouzivat +,-,* a zavorky.

rovnice(X,Y) --> vyraz(X),"=",vyraz(Y).

vyraz(Z) --> vyraz_aux(S),{secti(S,Z)}.

vyraz_aux([Z|S]) --> cislo(Z),"+",vyraz_aux(S).
vyraz_aux([Z,Y|S]) --> cislo(Z),"-",vyraz_aux([X|S]),{Y is 0 - X}.
vyraz_aux([Z|S]) --> cislo(X),"*",vyraz_aux([Y|S]),{Z is X * Y}.
vyraz_aux([Z]) --> cislo(Z).

cislo(Z) --> "(",vyraz(Z),")".  
cislo(Z) --> cislo_aux(Z,N).

cislo_aux(Z,10*N) --> cislice(X),cislo_aux(Y,N),{Z is (N * X) + Y}.
cislo_aux(Z,10) --> cislice(Z).

% -----------------------------------------------------
% secti(S,Z) secte prvky v seznamu S a vysledek da do Z

secti([H|T],X) :- secti(T,Y),X is H + Y.
secti([],0).

% =====================================================
% 5. - gramatika pracujici na reversu vstupu
% =====================================================
% gramatika je navrzena tak, aby pracovala korektne nad 
% prevracenym vstupem (pracuje podobne jako gramatika 
% popsana v casti 3, ale ted je pravorekurzivni a proto necykli)  
% gramatika dovoluje pouzivat +,- a zavorky

rovnice2(X,Y) --> vyraz2(X),"=",vyraz2(Y).

vyraz2(Z) --> cislo2(Y),"+",vyraz2(X),{Z is X + Y}.
vyraz2(Z) --> cislo2(Y),"-",vyraz2(X),{Z is X - Y}.
vyraz2(Z) --> cislo2(Z).

cislo2(Z) --> "(",vyraz2(Z),")". 
cislo2(Z) --> cislice(Y),cislo2(X),{Z is (10 * X) + Y}.
cislo2(Z) --> cislice(Z).

% -----------------------------------------------------
% otoc(X,Y) prevrati seznam X a vysledek da do Y

otoc(X,Y) :- otoc_aux(X,Y,[]).

otoc_aux([H|T],Y,Z) :- otoc_aux(T,Y,[H|Z]).
otoc_aux([],Y,Y).

% =====================================================
% 6. - chybna gramatika z manualu sicstu
% =====================================================
% umi pracovat pouze s jednomistnymi cisly
% spatne vyhodnocuje: 9-3-2 vyhodnoti na 8 misto 4.

expr(Z) --> term(X), "+", expr(Y), {Z is X + Y}.
expr(Z) --> term(X), "-", expr(Y), {Z is X - Y}.
expr(X) --> term(X).
     
term(Z) --> number(X), "*", term(Y), {Z is X * Y}.
term(Z) --> number(X), "/", term(Y), {Z is X / Y}.
term(Z) --> number(Z).
     
number(C) --> "+", number(C).
number(C) --> "-", number(X), {C is -X}.
number(X) --> [C], {"0"=<C, C=<"9", X is C - "0"}.
