Per quel che riguarda l'AL molto è già stato detto nella sezione dedicata all'interprete Scheme. La soluzione è la stessa, ovvero l'AL è al solito composto da un lexer detto PrologLexer (che costituisce una sottoclasse della generica classe Lexer definita nel package Interpreter.Sexp.Utils.Lexer) e dai soliti quattro set (PrimitiveSet, OperationalSet, RelationalSet e SpecialSet). L'AL Prolog è quindi organizzato esattamente allo stesso modo dell'AL Scheme.
Vi sono però due osservazioni da fare.
La prima osservazione da fare riguarda il fatto che in Prolog le parentesi tonde hanno una duplice funzione: se si scrive "append(L1,L2,R)" si intende indicare il termine append/3 e quindi le parentesi tonde racchiudono i suoi argomenti, mentre se si scrive "3*(5-2)" le parentesi servono a far eseguire la sottrazione prima della moltiplicazione, ovvero intervengono sulla precedenza fra gli operatori. Tuttavia in Prolog un operatore è anche un funtore, quindi l'espressione aritmetica precedente può essere anche scritta come *(3, -(5, 2)), ovvero termine con funtore '*' (mettiamo gli apici solo per evidenziare che si tratta di funtori) e due argomenti, di cui il primo è il numero 3 ed il secondo è il termine con funtore '-' e due argomenti dati dai numeri 5 e 2. Allora nasce un problema nel caso di operatori prefissi. Per capire il problema chiediamoci come deve interpretare l'interprete il seguente codice:
:-(a,b).Ci sono due possibilità, la prima è di interpretarlo come un termine di tipo ':-'/2 con argomenti a e b, la seconda è di intenderlo come termine ':-'/1 con argomento l'and di a e b. Nel primo caso quella scrittura rappresenta una clausola con antecedente "a" e conseguente "b", nel secondo rappresenta una query con body l'and di "a" e "b". L'espressione è in effetti ambigua e quindi può portare a degli errori. La soluzione adottata in SICStus (http://www.sics.se/sicstus.html) è stata quella di imporre una restrizione sintattica per superare l'ambiguità. Si tratta semplicemente di imporre che allorché si voglia scrivere un termine nella forma "funtore" + "(" + "elenco argomenti" + ")" non si devono interporre dei caratteri di separazione (come ad esempio lo space) fra il nome del funtore e la "(". In questo modo l'esempio sopra deve essere inteso come termine di tipo :-/2, poiché l'aperta parentesi non è separata dal funtore. Se si scrive quindi:
Nel nostro caso non era semplice ottenere la stessa cosa. Questo fatto è ancora una volta imputabile allo StreamTokenizer di Java. Infatti il vantaggio di usare lo StreamTokenizer è che si può delegare ad esso il compito di costruire i token indicandogli semplicemente quali sono i separatori (space, new line, tab...), ma così facendo non è più possibile sapere se due token successivi sono o no intercalati da qualche separatore. In particolare non è possibile sapere se una stringa ed un'aperta parentesi tonda sono separati o no. L'unico modo per saperlo è di farsi restituire dallo StreamTokenizer anche i separatori e trattarli nel proprio lexer. Ciò che si dovrebbe fare è di definire una sottoclasse dello StreamTokenizer ed in essa aggiungere un flag, che si potrebbe chiamare nospaces, e ridefinire il metodo next(). All'interno di next() si dovrebbe inizialmente resettare flag, poi effettuare un ciclo in cui per prima cosa si chiama super.next() e se viene restituito un separatore allora lo si "scarta" e si setta il flag. Il ciclo terminerebbe allorché super.next() restituisce un token che non sia un separatore. A questo punto si può restituire quel token e terminare. Quel flag sarà settato se sono stati incontrati dei separatori prima del token, oppure non settato in caso contrario. Se si vuole a questo punto sapere se il token corrente (questo potrebbe essere appunto l'aperta parentesi) era o no preceduto da separatori è sufficiente controllare quel flag. La scomodità di questa soluzione è che si deve ridefinire la classe StreamTokenizer e riscrivere la gestione degli spazi solo per poter avere quel flag. La soluzione migliore sarebbe avere quel flag direttamente nello StreamTokenizer.
La seconda osservazione da fare riguardo all'AL è legata al riconoscimento di token come ":-", oppure "=:=", etc. Si tratta di tokens costruiti unendo caratteri particolari che possono aver significato anche singolarmente. Per riconoscerli l'ideale sarebbe che lo StreamTokenizer mettesse a disposizione un metodo atom(String) tramite cui fosse possibile segnalargli quali sono gli atomi particolari che deve riconoscere.
Per questi motivi e per il problema legato al riconoscimento dei numeri (vedi sezione AL nella pagina dedicata all'implementazione dell'interprete Scheme) abbiamo pensato di definire una classe chiamata StreamTokenizerWithAtom, il cui codice è esattamente il codice della classe StreamTokenizer Java modificato aggiungendogli tutte le funzionalità che ci servivano, ovvero: