%--------------------------- Nyelvtan szamok felismeresere -----------------------------


% Egy DCG nyelvtant betoltve a prologba az interpreter a nem-terminalisokbol
% predikatumokat, a nyelvtani szabalyokbol pedig prolog szabalyokat keszit.
% Nem-terminalisok: barmely Prolog term, mely nem valtozo es nem szam.
% Terminalisok: Prolog listaban felsorolt Prolog term(ek).
% Az elso pelda DCG nyelvtanra egy szamot felismero nyelvtan.

szam --> jegy, maradek.
maradek --> jegy, !, maradek; "".
jegy --> "0"; "1"; "2"; "3"; "4"; "5"; "6"; "7"; "8"; "9".

% Megj. 1: a kettos idezojel koze irt szoveg a prologban azt a listat reprezentalja,
% melynek elso eleme a szoveg elso karakterenek a kodja, masodik a masodike, stb.
% A masodik szabaly jobb oldalan levo "" azt jelenti, hogy a szabaly bal oldalan
% levo, maradek nevu nem-terminalis atirhato az ures szova.
% Megj. 2: a prolog szabalyoknal megszokottakkal analog modon a DCG nyelvtanoknal is
% pontosvesszo hasznalhato a logikai vagy jelzesere.


% A fenti nyelvtan betoltese utan a kovetkezokeppen donthetjuk el egy valtozorol, hogy
% szamot kodol-e, vagy sem:
% ?- A="143", szam(A,[]).


% A prolog interpreter altal a nem-terminalisokhoz felvett predikatumok aritasa mindig
% kettovel nagyobb lesz az adott nem-terminalis aritasanal (a fenti pelda eseten igy
% mindegyik 2 aritasu lesz). Az elso parameter tartalmazza mindig a feldolgozando szonak
% az adott nem-terminalis feldolgozasa elott meg hatra levo reszet, a masodik pedig a
% nem-terminalis feldolgozasa utan meg hatra levot. Ennek megfeleloen egy
% p --> q, r, s.
% szabalyt az interpreter a kovetkezo prolog szabalyra irja at:
% p(S0, S) :- q(S0, S1), r(S1, S2), s(S2, S).


%---------------- Nyelvtan szamok felismeresere es ertekuk kiszamitasara ----------------


% Extra feltetelek is betehetok a szabalyokba prolog fuggvenyhivas formajaban,
% kapcsos zarojelek koze teve.

% A nem-terminalisokat parameterekkel ellatva nemcsak azt ellenorizhetjuk, hogy a
% feldolgozando szo szam-e, hanem azt is kiszamithatjuk, mi az erteke:

szam(Sz) --> jegy(J), maradek(J,Sz).
maradek(Sz0,Sz) --> jegy(J), !, {Sz1 is Sz0*10+J}, maradek(Sz1,Sz); "", {Sz=Sz0}.
jegy(J) --> [D], {D>47, D<58, J is D-48}. %A D-ben levo karakterkod 0'0 es 0'9 koze esik.

% Az extra feltetelek a termeszetes modon/formaban kerulnek be az interpreter altal
% letrehozott prolog szabalyokba.

% A terminalisokat a prolog egy beepitett 'C'/3 predikatum segitsegevel irja at, ami a
% 'C'([X|S], X, S).
% szaballyal van definialva. Az elso (illetve az utolso) parameter - a korabbiaknak
% megfeleloen - a feldolgozando szonak a nemterminalis feldolgozasa elott (illetve utan)
% meg hatralevo resze, a kozepso pedig az adott terminalis. Ennek megfeleloen pl. egy
% p(X) --> [go,to], q(X), [stop].
% szabaly a
% p(X, S0, S):- 'C'(S0, go, S1), 'C'(S1, to, S2), q(X, S2, S3), 'C'(S3, stop, S).
% szaballya konvertalodik; a fenti nyelvtan utolso szabalyabol pedig ez lesz:
% jegy(J,S0,S):- 'C'(S0,D,S1), D>47, D<58, J is D-48.

% A szamellenorzo uj valtozata peldaul igy hasznalhato:
% ?- A="143", szam(Ertek,A,[]).


%--------------------- Aritmetikai kifejezesek szintaktikai elemzese --------------------


kif --> tag, "+", !, kif.
kif --> tag, "-", !, kif.
kif --> tag.
tag --> fakt, "*", !, tag.
tag --> fakt, "/", !, tag.
tag --> fakt.
fakt --> szam, !.
fakt --> "-", !, szam.
fakt --> "(", kif, ")".

% ?- kif("-2+3*(5+1)",[]).


%--------------------- Aritmetikai kifejezesek ertekenek kiszamitasa -------------------


kif(K) --> tag(T), "+", kif(K0), !, {K is T+K0}.
kif(K) --> tag(T), "-", kif(K0), !, {K is T-K0}.
kif(K) --> tag(K).

tag(T) --> fakt(F), "*", tag(T0), !, {T is F*T0}.
tag(T) --> fakt(F), "/", tag(T0), !, {T is F/T0}.
tag(T) --> fakt(T).

fakt(F) --> szam(F), !.
fakt(F) --> "-", szam(Sz), !, {F is -Sz}.
fakt(F) --> "(", kif(F), ")".

% ?- kif(Eredmeny,"-2+3*(5+1)",[]).
% Vigyázat, a fenti program a kifejezéseket nem helyesen zárójelezi! A korrekt végeredmény
% eléréséhez magunknak kell a megfelelő zárójelezésről gondoskodni. Lásd a
% ?- kif(Eredmeny,"2-3+10",[]).
% és a
% ?- kif(Eredmeny,"(2-3)+10",[]).
% példákat.
% Egy megoldás ennek orvoslására