L'idea iniziale di definire un interprete Prolog
semplificato prevedeva la costruzione di un AS (classe Parser) molto specifico,
cioè dipendente dagli operatori predefiniti. Era infatti legato
ad una grammatica in cui si prevedeva che una clausola fosse data da un
antecedente seguito dal simbolo :- e da un body che a sua volta era dato
dall'or di termini and che a loro volta potevano essere costituiti da termini,
da espressioni is, etc. La grammatica quindi esplicitava tutti gli operatori
(vedi grammPrSempl.txt).
Successivamente abbiamo trovato motivi validi per
modificare radicalmente il Parser. L'osservazione principale è che
in Prolog è possibile definire runtime nuovi operatori (tramite
il predicato op/3) e dunque la grammatica dovrebbe essere modificata
dinamicamente. Poiché abbiamo abbandonato l'idea iniziale di fare
un interprete semplificato risultava a quel punto più semplice l'introduzione
di tutti gli operatori built-in utilizzando un Parser generico e dinamicamente
adattabile.
La filosofia del nuovo Parser (classe NewParser)
si basa sul fatto che tutti gli operatori Prolog sono essi stessi dei termini,
perché in Prolog non vi è distinzione fra dati e programmi.
Gli operatori Prolog possono essere binari o unari e questi ultimi possono
essere prefissi o postfissi. Inoltre ogni operatore può essere o
non essere associativo (i binari possono avere associatività a destra
o a sinistra). Ciascun operatore ha poi una priorità
(un intero compreso fra 0 e 1200) che serve a stabilire la precedenza degli
operatori in modo da eliminare le ambiguità.
L'operatore op/3 prevede di indicare il tipo
dell'operatore come segue:
non associativo | associativo a sinistra | associativo a destra | |
prefissi (unari) | fx | fy | |
infissi (binari) | xfx | yfx | xfy |
postfissi (unari) | xf | yf |
in cui:
Clause ->
Read(1200) .Read(N) ->
Op(N,M,fx) Read(M-1) Rest(N,M)
Op(N,M,fx) Read(M-1)
Op(N,M,fy) Read(M) Rest(N,0)
Op(N,M,fy) Read(M)
Term Rest(N,0)
TermRest(N,M) ->
Op(N,M1,xfx) Read(M1-1) Rest(N,M1) {M1>M}
Op(N,M1,xfx) Read(M1-1) {M1>M}
Op(N,M1,xfy) Read(M1) Rest(N,M1) {M1>M}
Op(N,M1,xfy) Read(M1)
Op(N,M1,yfx) Read(M1-1) Rest(N,M1)
Op(N,M1,yfx) Read(M1-1)
Op(N,M1,xf) Rest(N,M1) {M1>M}
Op(N,M1,xf)
Op(N,M1,yf) Rest(N,M1)
Op(N,M1,yf)Term ->
Num
Var
List
Ident
Ident ( Args
NoArgs
( Read(1200) )Num ->
un numeroVar ->
una stringa che inizi con una lettera maiuscola o con un _List ->
[ ]
[ RestListRestList ->
Read(999) , RestList
Read(999) | Read(999) ]
Read(999) ]Ident ->
tutte le stringhe che non sono variabili o numeriArgs ->
Read(999) , Args
Read(999) )NoArgs ->
!
not
nlOp(N,M,T) ->
operatore di tipo T e priorità M, con T Î {fx, fy, xfx, xfy, yfx, xf, yf} e con M<N
Osservazioni.