javacc Analisi Lessicale

Transcript

javacc Analisi Lessicale
javacc
Analisi Lessicale
Nicola Fanizzi
Corso di Linguaggi di Programmazione
Dipartimento di Informatica
Università degli Studi di Bari
10 aprile 2014
Sommario
1
2
3
JavaCC
Installazione
Nozioni Preliminari
Espressioni Regolari Estese
Operatori
Insiemi di Caratteri
Denominazione dei token
File di specifica
Sezioni
N. Fanizzi
Linguaggi di prog.+Lab
4
5
File prodotti da JavaCC
Regole di match del token
manager
Azioni nel token manager
Opzioni & Debug
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole MORE
Esercizi
javacc – Analisi Lessicale
10 aprile 2014
2 / 75
JavaCC
Sommario
1
2
3
JavaCC
Installazione
Nozioni Preliminari
Espressioni Regolari Estese
Operatori
Insiemi di Caratteri
Denominazione dei token
File di specifica
Sezioni
N. Fanizzi
Linguaggi di prog.+Lab
4
5
File prodotti da JavaCC
Regole di match del token
manager
Azioni nel token manager
Opzioni & Debug
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole MORE
Esercizi
javacc – Analisi Lessicale
10 aprile 2014
3 / 75
JavaCC
Installazione
JavaCC
JavaCC = Java Compiler Compiler
Partendo dalla specifica di una grammatica, genera
le classi Java che realizzano
un analizzatore sintattico top-down ed
un analizzatore lessicale per tale grammatica
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
4 / 75
JavaCC
Installazione
Installazione JavaCC
Siti ufficiali:
http://javacc.java.net/
http://java.net/projects/javacc
Versione corrente 5.0
Multipiattaforma:
Pacchetto in molte distribuzioni GNU/Linux
es. per Ubuntu-Linux
http://packages.ubuntu.com/search?keywords=javacc
per Windows: decomprimere e settare opportunamente le
var. d’ambiente PATH e CLASSPATH
Plugin per IDE Java principali
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
5 / 75
JavaCC
Nozioni Preliminari
Generazione Automatica con JavaCC I
Si possono usare programmi detti token manager generator
(detti anche lexical analyzer generator) per scrivere un token
manager
Si danno in input espressioni regolari che definiscono i token
che si vogliono identificare
Il generatore di token manager produrrà il token manager
corrispondente in Java
espressione
regolare
N. Fanizzi
Linguaggi di prog.+Lab
generatore di
token
manager
javacc – Analisi Lessicale
codice Java
del TM
10 aprile 2014
6 / 75
JavaCC
Nozioni Preliminari
Generazione Automatica con JavaCC II
Si può usare un programma analogo parser generator per
scrivere l’analizzatore sintattico.
si dà in input una grammatica del linguaggio
il generatore restituisce il parser in Java
grammatica
del linguaggio
generatore di
parser
codice Java
del parser
Ci soffermeremo sull’approccio top-down ricorsivo discendente:
per ogni non-terminale si scrive un metodo basato sulle
produzioni della grammatica
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
7 / 75
JavaCC
Nozioni Preliminari
Generazione Automatica con JavaCC III
JavaCC combina i generatori di token manager e di parser
effettua a sua volta una compilazione:
traduce il suo input in un compilatore
pertanto appartiene alla categoria dei compiler-compiler
(compilatori di compilatori), da cui il suffisso nel nome
accetta un file di specifica contenente
espressioni regolari (per il token manager)
grammatica (specifica per il parser o traduttore)
espressioni
regolari
JavaCC
codice Java
del compilatore
grammatica
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
8 / 75
JavaCC
Nozioni Preliminari
Generazione Automatica con JavaCC IV
Vantaggi dell’uso di JavaCC
1
si riduce il tempo di produzione di un compilatore
2
si producono compilatori più affidabili
la maggioranza dei bachi nei compilatori scritti a mano sono
introdotti nel processo di calcolo degli insiemi di selezione
(first+follow)
JavaCC solleva da questi compiti e li svolge automaticamente,
producendo meno errori (nessuno se si danno specifiche
corrette)
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
9 / 75
JavaCC
Nozioni Preliminari
Token Manager I
Il Token Manager (detto anche scanner o lexer)
analizza il flusso di caratteri in input spezzandolo in
sequenze riconosciute dette lessemi
assegnando ad ognuno di loro un tipo o token
spesso si usa lo stesso nome (token) per entrambi
Esempio
(sorgente in C):
int main() {
/* a short program */
3
return 0; }
1
2
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
10 / 75
JavaCC
Nozioni Preliminari
Token Manager II
int main() {
/* a short program */
3
return 0; }
1
2
Il token manager divide il flusso nelle seguenti stringhe:
"int", " ", "main", "(", ")", " ", "{", "\n", "\t",
"/* a short program */", "\n", "\t", "return", . . .
Spaziatura e commenti tipicamente vengono saltati
Ogni stringa viene classificata secondo uno dei tipi di token:
Ad es. nel caso precedente:
KWINT, ID, LPAR, RPAR, LBRACE, KWRETURN, INTCONST,
SEMICOLON, RBRACE
I pattern che permettono di operare questo riconoscimento
e di far generare automaticamente l’automa relativo,
sono descritti attraverso espressioni regolari
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
11 / 75
Espressioni Regolari Estese
Sommario
1
2
3
JavaCC
Installazione
Nozioni Preliminari
Espressioni Regolari Estese
Operatori
Insiemi di Caratteri
Denominazione dei token
File di specifica
Sezioni
N. Fanizzi
Linguaggi di prog.+Lab
4
5
File prodotti da JavaCC
Regole di match del token
manager
Azioni nel token manager
Opzioni & Debug
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole MORE
Esercizi
javacc – Analisi Lessicale
10 aprile 2014
12 / 75
Espressioni Regolari Estese
Espressioni Regolari Estese I
Nelle espressioni regolari estese di JavaCC,
i simboli dell’alfabeto vanno racchiusi tra doppi apici
Esempio (doppi apici)
per rappresentare le due stringhe "b" e "c":
"b"|"c"
I doppi-apici aiutano a distinguere i simboli dell’alfabeto dai
meta-simboli, come le parentesi e gli operatori
Esempio (doppi apici – cont.)
La barra verticale è un operatore (non è racchiusa tra i doppi
apici)
Invece, "b|c" rappresenta la sola stringa "b|c"
Qui la barra è un carattere da interpretare letteralmente
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
13 / 75
Espressioni Regolari Estese
Espressioni Regolari Estese II
Esempio (spazi ignorati)
"a"|"z" e "a"| "z" sono equivalenti
Ma "a"|"z" e "a "|"z" non lo sono;
lo spazio dopo la a nell’ultima espressione è all’interno degli apici
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
14 / 75
Espressioni Regolari Estese
Operatori
Operatori
Operatori (postfissi) per iterazione / selezione
* (zero o più)
+ (uno o più)
? (zero o uno)
JavaCC richiede che gli argomenti di questi operatori siano
racchiusi tra parentesi tonde
Esempio (iterazione)
per indicare tutte le stringe di zero o più b,
si scrive ("b")* e non "b"*
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
15 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Insiemi di Caratteri I
Usando le par. quadre ([ ]),
si specifica un insieme di caratteri singoli;
elementi successivi vanno separati con delle virgole (,):
Esempio (insiemi di caratteri)
per indicare l’insieme contenente b, c e d
si può scrivere ["b","c","d"]
che è anche equivalente a "b"|"c"|"d"
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
16 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Insiemi di Caratteri II
Si possono anche specificare intervalli di caratteri usando il
trattino (-) tra due caratteri:
Esempio (intervalli di caratteri)
per specificare tutte le lettere maiuscole e minuscole
si possono indicare gli intervalli da A a Z e da a a z tra quadre:
["A"-"Z","a"-"z"]
che risulta molto più compatta dell’elenco di 52 lettere
["A","B",. . . ,"Z","a","b",. . . ,"z"]
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
17 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Insiemi di Caratteri III
NB: nelle quadre vanno solo caratteri singoli e non stringhe:
Esempio (intervalli di caratteri – errori tipici)
["a"-"z", "AZ", "\n"] è un’espressione errata:
"a"-"z" e "\n" sono leciti (range e singolo car. di newline),
invece "AZ" è una stringa
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
18 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Insiemi di Caratteri IV
L’operatore di complemento ~
si applica solo ad insiemi di caratteri definiti con l’op. [ ]
Esempio (complemento di set di caratteri)
~["z"] rappresenta tutti i caratteri tranne la z
~["a","z"] rappresenta tutti i caratteri tranne a e z
Invece non è lecita l’espressione: ~"z"
il complemento è definito per set di caratteri non per caratteri
singoli
Diversamente da *, + e ?, non si usano le tonde con l’operatore ~:
Esempio (complemento – errori tipici)
~(["z"]) errata, ~("z") errata
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
19 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Insiemi di Caratteri V
[] rappresenta l’insieme vuoto,
quindi ~[] rappresenta tutti i caratteri disponibili
Esercizio Scrivere un’espressione regolare estesa che
rappresenti l’insieme di tutte le possibili stringhe
Risposta: (~[])*
Si noti che le parentesi tonde servono all’op. * non a ~
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
20 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Esempio – token per le costanti numeriche I
Si definiscano i token per gli interi senza segno:
uno o più cifre
(["0"-"9"])+
Si supponga di voler specificare anche i numeri senza segno ma
con la parte decimale: 68, 3.14, 54., .22
Prima proposta (zero o più cifre prima o dopo il punto decimale):
(["0"-"9"])* "."(["0"-"9"])*
non funziona per numeri come 68
comprende anche il caso (errato) della stringa “.”
Dividiamo le stringhe nei vari casi:
1
cifre senza punto decimale (come 68)
2
cifre prima e dopo il punto decimale (come 3.14)
3
cifre solo prima del punto decimale (come 54.)
4
cifre solo dopo il punto decimale (come .22)
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
21 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Esempio – token per le costanti numeriche II
Si può scrivere l’espressione cercata, unendo 4 espressioni con |
(1)
(2)
(3)
(4)
che equivale a:
(["0"-"9"])+
(1)
| (["0"-"9"])+ "." (["0"-"9"])*
(2+3)
| "." (["0"-"9"])+
(4)
(["0"-"9"])+
| (["0"-"9"])+ "." (["0"-"9"])+
| (["0"-"9"])+ "." |
| "." (["0"-"9"])+
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
22 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Esempio – token per identificatori
Fornire l’espressione regolare per identificatori fatti da una lettera
eventualmente seguita da lettere o cifre.
Una soluzione
["A"-"Z", "a"-"z"] (["A"-"Z","a"-"z","0"-"9"])*
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
23 / 75
Espressioni Regolari Estese
Insiemi di Caratteri
Caratteri speciali
Siccome doppi apici (") e backslash (\) sono caratteri speciali
se si vuole specificare letteralmente uno di essi (escape)
bisognerà farlo precedere da un backslash
Esempio (escape)
per specificare la stringa fatta da A, \, " e Z si scrive
"A\\\"Z"
Alcuni altri caratteri normali, preceduti da backslash, hanno
significati speciali. Ad esempio,
"\n" newline
"\r" return
"\t" tab
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
24 / 75
Espressioni Regolari Estese
Denominazione dei token
Denominazione dei token I
JavaCC consente di dare un nome alle espressioni regolari:
si racchiudono nome ed espressione tra partentesi angolari < >,
separandoli con :
Esempio (nomi di espressioni)
per associare il nome UNSIGNED all’espressione regolare per gli
interi senza segno, si scrive
<UNSIGNED: (["0"-"9"])+>
Per convenzione, si usano le MAIUSCOLE per i nomi, come
per le costanti Java
Associato un nome ad una espressione, ci si può riferire alla
categoria di token mediante tale nome
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
25 / 75
Espressioni Regolari Estese
Denominazione dei token
Denominazione dei token II
Dato un nome ad un’espressione, lo si può riusare (tra parentesi
angolari) per definire altre espressioni:
Esempio (riutilizzare i nomi)
Data <DIGIT: ["0"-"9"]> si può riscrivere l’espressione per gli
interi senza segno come segue:
<UNSIGNED: (<DIGIT>)+>
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
26 / 75
File di specifica
Sommario
1
2
3
JavaCC
Installazione
Nozioni Preliminari
Espressioni Regolari Estese
Operatori
Insiemi di Caratteri
Denominazione dei token
File di specifica
Sezioni
N. Fanizzi
Linguaggi di prog.+Lab
4
5
File prodotti da JavaCC
Regole di match del token
manager
Azioni nel token manager
Opzioni & Debug
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole MORE
Esercizi
javacc – Analisi Lessicale
10 aprile 2014
27 / 75
File di specifica
File di specifica I
I file di specifica di JavaCC per convenzione hanno estensione .jj
Struttura di un tipico file
options {
// opzioni di JavaCC
3}
1
2
4
PARSER_BEGIN(NomeParser)
// Sezione per la classe del parser e classi accessorie
7 PARSER_END(NomeParser)
5
6
8
TOKEN_MGR_DECLS: {
// dichiarazioni di var e metodi per il token manager
11 }
9
10
12
SKIP: {
// espr.reg. di token da saltare senza passarle al parser
15 }
13
14
16
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
28 / 75
File di specifica
File di specifica II
TOKEN: {
// espr.reg. di token da riconoscere e passare al parser
19 }
17
18
20
21
// sezione della grammatica
Sono consentiti commenti Java-style, su singola linea con // o su
più linee, delimitati da /* e */
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
29 / 75
File di specifica
Sezioni
Sezioni I
la sez. options serve a settare opzioni di JavaCC.
Es. STATIC = false; serve a generare metodi non statici
la sez. PARSER_BEGIN/PARSER_END contiene il codice Java da
fornire a JavaCC
deve contenere almeno la classe del parser
(indicata tra parentesi)
classi addizionali
(es. per la symbol table o generatore di codice)
non è obbligatorio che la classe parser contenga codice Java
1
2
3
4
5
6
7
8
9
N. Fanizzi
PARSER_BEGIN (Sample)
public class Sample {
/*
public static void main (String[] args) {
...
}
*/
}
PARSER_END (Sample)
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
30 / 75
File di specifica
Sezioni
Sezioni II
la sez. TOKEN_MGR_DECLS contiene dichiarazioni di variabili e
metodi ad uso del token manager
una sez. SKIP contiene espressioni regolari per i token che il
token manager non deve passare al parser
SKIP: {
" "
3
| "\n"
4
| "\r"
5
| "\t"
6}
1
2
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
31 / 75
File di specifica
Sezioni
Sezioni III
la sez. TOKEN contiene espressioni regolari per i token che il
token manager deve passare al parser; i nomi saranno poi
utilizzati nella grammatica
TOKEN: {
<PRINTF: "printf"> |
3
<UNSIGNED: (["0"-"9"])+> |
4
<ID: ["A"-"Z","a"-"z"] (["A"-"Z","a"-"z","0"-"9"])*>
5}
1
2
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
32 / 75
File di specifica
Sezioni
Sezioni IV
L’ordine conta: se due espressioni corrispondono alla stessa
immagine di car. in input, JavaCC userà la prima della lista
ad es. se si leggesse la stringa printf sull’input,
sia <PRINTF> sia <ID> troverebbero corrispondenza;
ma sarebbe restituito <PRINTF> che viene prima
in alternativa, si può specificare "printf" come token
anonimo nella grammatica per il parser
NB: i token anonimi sono considerati come inseriti
virtualmente alla fine della sez. TOKEN
I token elencati nelle sez. TOKEN e SKIP che non siano stringhe
letterali vanno delimitati da par. angolari:
TOKEN: {
("i")+ // errato, dovrebbe essere <("i")+>
3
"while" // corretto, scritto anche <"while">
4}
1
2
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
33 / 75
File di specifica
File prodotti da JavaCC
File prodotti da JavaCC
Classi generiche (file prodotti se non già esistenti)
SimpleCharStream.java flussi di caratteri in input
Token.java classe degli oggetti token
TokenMgrError.java errore dell’analizzatore lessicale
ParseException.java eccezioni: non conformità alla
grammatica del parser
Classi/interfacce specifiche (prefisso NN)
NN.java classe del parser
NNTokenManager.java classe dell’analizzatore lessicale;
contiene il metodo getNextToken()
NNConstants.java interfaccia che associa nomi simbolici
(costanti) alle classi di token
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
34 / 75
File di specifica
File prodotti da JavaCC
Metodo getNextToken()
Il metodo getNextToken() del token manager
implementa la simulazione del DFA che riconosce i token
descritti dalle espressioni regolari
alla chiamata
cerca la corrispondenza tra le espressioni regolari e
le stringhe di caratteri nelle sequenza di input
restituisce il token (oggetto) relativo alla prima
corrispondenza trovata
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
35 / 75
File di specifica
File prodotti da JavaCC
Classe Token
Token.java contiene i campi:
1
public int kind;
// tipo di token
2
/* posizione di inizio e fine
del token nel file di input */
5 public int beginLine;
6 public int beginColumn;
7 public int endLine;
8 public int endColumn;
3
4
9
10
public String image;
N. Fanizzi
Linguaggi di prog.+Lab
// immagine del lessema
javacc – Analisi Lessicale
10 aprile 2014
36 / 75
File di specifica
File prodotti da JavaCC
Generazione del solo token manager I
Se non si include una grammatica,
JavaCC non genera il codice per il parser.
Il blocco PARSER_BEGIN/PARSER_END può essere usato per
codice Java ad uso del solo token manager
es. minimalmente per il main()
options {
STATIC = false;
3}
1
2
4
PARSER_BEGIN(SenzaParser)
import java.io.*;
7 class SenzaParser {
8
public static void main(String[] args) throws IOException {
9
Token t;
10
FileInputStream in=new FileInputStream(args[0]);
5
6
11
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
37 / 75
File di specifica
File prodotti da JavaCC
Generazione del solo token manager II
12
13
SenzaParserTokenManager tm =
new SenzaParserTokenManager(new SimpleCharStream(in));
14
t = tm.getNextToken();
while (t.kind != EOF) {
17
System.out.println(tokenImage[t.kind] + " " + t.kind);
18
t = tm.getNextToken();
19
} // while
20
} // main
21 } // class
22 PARSER_END(SenzaParser)
15
16
23
SKIP: {
" "
26
| "\n"
27
| "\r"
28
| "\t"
29 }
24
25
30
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
38 / 75
File di specifica
File prodotti da JavaCC
Generazione del solo token manager III
TOKEN: {
"printf" |
33
<UNSIGNED: (["0"-"9"])+> |
34
<ID: ["A"-"Z","a"-"z"] (["A"-"Z","a"-"z","0"-"9"])*> |
35
<ERROR: ~[]>
36 }
31
32
da cui, utilizzando un file contenente
1
345printf area x+
si otterrebbero le stampe1 :
<UNSIGNED> 345
"printf" printf
3 <ID> area
4 <ID> x
5 <ERROR> +
1
2
1
L’array String[] tokenImage è definito nel file dell’interfaccia con le
costanti SenzaParserConstants.java.
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
39 / 75
File di specifica
Regole di match del token manager
Regole di match del token manager I
Cercando la corrispondenza tra le espr. regolari e il flusso di
caratteri in input, il token manager generato segue 2 regole:
1
Cercare sempre il più lungo match possibile
Esempio (match)
1
2
3
TOKEN: {
<Ti: ("i")+>
}
Se si legge "iiixyz" allora <Ti> trova corrispondenza con tre
sotto-stringhe: "i", "ii" e "iii" ma il token manager restituirà la più
lunga "iii"
2
N. Fanizzi
A parità di lunghezza, si sceglie la corrispondenza che viene
prima nell’elenco.
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
40 / 75
File di specifica
Regole di match del token manager
Regole di match del token manager II
Esercizio
Data la sezione
TOKEN: {
<UNO: "123">
3
|
4
<DUE: "123456">
5}
1
2
Quale token verrebbe restituito,
se il token manager avesse in input "123456789" ?
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
41 / 75
File di specifica
Regole di match del token manager
Errori Lessicali I
TOKEN: {
<ASSIGN: "="> |
3
<UNSIGNED: (["0"-"9"])+> |
4
<ID: ["A"-"Z","a"-"z"] (["A"-"Z","a"-"z","0"-"9"])*>
5}
1
2
leggendo lato += 10 il token manager avrebbe un problema
su "+", e lancerebbe un’eccezione non essendo possibile
trovare alcuna corrispondenza nella sezione
Diversamente dal parser, esso non sa cosa aspettarsi dal
flusso quando incontra un car. non valido
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
42 / 75
File di specifica
Regole di match del token manager
Errori Lessicali II
Approccio alternativo
1
far restituire al token manager il bad token al parser.
Il parser potrebbe comprendere l’errore e lanciare
un’eccezione, segnalando un errore, con più info a
disposizione.
Vanno previsti appositi blocchi catch
2
per catturare i bad token, si può includere alla fine della sez.
TOKEN l’espr. <ERROR: ~[]> che rappresenta singoli caratteri
caveat: se si usassero token anonimi nella grammatica JavaCC
li includerebbe a fine sez. TOKEN dopo ERROR.
Conviene allora elencare nella sez. TOKEN tutti i token possibili
prima di ERROR
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
43 / 75
File di specifica
Regole di match del token manager
Regole SKIP / I
Le regole nel blocco SKIP indicano quello che va ignorato:
tipicamente i blank ma anche i commenti
SKIP:
{
3
<espressioneRegolare1>
4 |
<espressioneRegolare2>
5 |
...
6 |
<espressioneRegolaren>
7}
1
2
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
44 / 75
File di specifica
Regole di match del token manager
Regole SKIP / II
Esempio
1
2
PARSER BEGIN(File2)
3
4
public class File2{
5
6
}
7
8
PARSER END(File2)
9
SKIP:
{
12
<" ">
13 | <"\n">
14 | <"\t">
15 }
10
11
16
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
45 / 75
File di specifica
Regole di match del token manager
Regole SKIP / III
TOKEN:
{
19
<ELSE: "else">
20 | <SEMICOLON: ";">
21 | <FOR: "for">
22 | <UNSIGNED: (["0"-"9"])+>
23 | <IDENTIFIER: ["a"-"z"](["a"-"z","0"-"9"])*>
24 }
17
18
Per l’input:
1
2
else ;
23 for
viene restituita la sequenza:
<ELSE> <SEMICOLON> <UNSIGNED> <FOR>
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
46 / 75
File di specifica
Regole di match del token manager
Regole SKIP / IV
Esempio
Ignorare i commenti C++ (singola linea):
SKIP:
{
3
<"//" (~["\n"])* "\n">
4}
1
2
regola poco espressiva
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
47 / 75
File di specifica
Regole di match del token manager
Stati lessicali I
Ogni regola di tipo TOKEN o SKIP può essere etichettata con
uno stato lessicale
Le regole non etichettate sono considerate regole nello stato
lessicale DEFAULT
Il token manager deve trovare corrispondenze con le sole
regole etichettate con lo stato lessicale in cui si trova
<STATO_VECCHIO> // etichetta stato lessicale
SKIP:
3{
4
<EspressioneRegolare>: STATO_NUOVO
5}
1
2
Trovata la corrispondenza tra EspressioneRegolare e una
porzione dell’input, il token manager passa da STATOVECCHIO
a STATONUOVO
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
48 / 75
File di specifica
Regole di match del token manager
Stati lessicali II
1
...
2
SKIP: // stato di DEFAULT
{
<" ">
5|
<"\n">
6|
<"\t">
7}
3
4
8
SKIP: // stato di DEFAULT
{
11
<"/*"> : IN_COMMENTO
12 }
9
10
13
<IN_COMMENTO>
SKIP:
16 {
17
<"*/"> : DEFAULT
14
15
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
49 / 75
File di specifica
Regole di match del token manager
Stati lessicali III
18
19
| <~[]>
}
20
TOKEN:
{
23
<ELSE: "else">
24 | <SEMICOLON: ";">
25 | <FOR: "for">
26 | <UNSIGNED: (["0"-"9"])+>
27 | <IDENTIFIER: ["a"-"z"](["a"-"z","0"-"9"])*>
28 }
21
22
cosa succede con
1
2
else /* commento */
12/* commento */;
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
50 / 75
File di specifica
Azioni nel token manager
Azioni nel token manager I
Si possono associare azioni alle espr. regolari per definire il
funzionamento del token manager.
L’azione viene eseguita in corrispondenza del match con
l’espressione che la precede
Le azioni sono espresse (come anche nella grammatica)
attraverso codice Java tra graffe
Esempio
TOKEN: {
... |
3
<UNSIGNED: (["0"-"9"])+>
4
{ System.out.println("UNSIGNED"); } |
5 ...
6}
1
2
stampa UNSIGNED ogni volta che si restituisce un token al parser
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
51 / 75
File di specifica
Azioni nel token manager
Azioni nel token manager II
Il token restituito è disponibile attraverso la variabile
matchedToken che può essere usata anche nelle azioni
Esempio
TOKEN: {
... |
3
<UNSIGNED: (["0"-"9"])+>
4
{ System.out.println ("immagine: " + matchedToken.image);} |
5 ...
6}
1
2
ogni volta che si trova un tokan UNSIGNED, viene mostrato il
campo image del token
Ad es. se l’input fosse 123 7645 allora si mostrerebbe:
immagine: 123
immagine: 7645
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
52 / 75
File di specifica
Azioni nel token manager
Azioni nel token manager III
Supponendo di voler mostrare l’immagine di ogni token passato
al parser senza aggiungere tante azioni come quella dell’esempio
si mette l’azione nel metodo CommonTokenAction
aggiungendolo alla sezione TOKEN_MGR_DECLS e si setta
COMMON_TOKEN_ACTION a true nella sezione options
Il token manager chiamerà CommonTokenAction passandogli il
token corrente prima di fornirlo al parser
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
53 / 75
File di specifica
Azioni nel token manager
Esempio
options {
STATIC = false;
3
COMMON_TOKEN_ACTION = true;
4}
1
2
5
PARSER_BEGIN(NomeParser)
public class NomeParser {
8
/* specifica della classe del parser */
9}
6
7
10
11
12
/* specifica classi accessorie */
PARSER_END(NomeParser)
13
TOKEN_MGR_DECLS: {
void CommonTokenAction() {
16
System.out.println ("immagine: " + matchedToken.image);
17
}
18 }
14
15
19
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
54 / 75
File di specifica
Azioni nel token manager
SKIP: {
" "
22
| "\n"
23
| "\r"
24
| "\t"
25 }
20
21
26
TOKEN: {
<ASSIGN: "="> |
29
<SEMICOLON: ";"> |
30
<LPAR: "("> |
31
<RPAR: ")"> |
32
<MINUS: "-"> |
33
<PLUS: "+"> |
34
<UNSIGNED: (["0"-"9"])+> |
35
<ID: ["A"-"Z","a"-"z"] (["A"-"Z","a"-"z","0"-"9"])*> |
36
<ERROR: ~[]>
37 }
27
28
38
39
// sezione della grammatica
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
55 / 75
File di specifica
Azioni nel token manager
Data in input
area = 12;
il token manager stamperebbe:
immagine:
immagine:
3 immagine:
4 immagine:
1
2
N. Fanizzi
area
=
12
;
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
56 / 75
File di specifica
Esempio
Azioni nel token manager
rimozione commenti
PARSER_BEGIN(RimCommenti)
public class RimCommenti {
3}
4 PARSER_END(RimCommenti)
1
2
5
TOKEN_MGR_DECLS:
{
8
public static int numCommenti = 0;
9}
6
7
10
SKIP:
{
13
<"/*"> : IN_COMMENTO
14 }
11
12
15
SKIP:
{
18
<"//" (~["\n"])* "\n" > { numCommenti++;}
16
17
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
57 / 75
File di specifica
19
Azioni nel token manager
}
20
<IN_COMMENTO>
SKIP :
23 {
24
<"*/"> { numCommenti++; SwitchTo(DEFAULT);}
25
// altra maniera per cambiare stato
26 }
21
22
27
<IN_COMMENTO>
SKIP :
30 {
31
< ~[] >
32 }
28
29
33
TOKEN :
{
36
<ANY: ~[]>
37 }
34
35
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
58 / 75
File di specifica
Opzioni & Debug
Opzioni
Le opzioni si settano un assegnazione nella sez. options block
oppure sulla linea di comando, ad es.:
javacc -NOSTATIC -COMMON_TOKEN_ACTION Parser.jj
settano STATIC a false e COMMON_TOKEN_ACTION a true
Ogni opzione booleana ha il corrispondente opposto con
prefisso NO
STATIC / NOSTATIC
COMMON_TOKEN_ACTION ha il val. default false
Se si usano entrambe le modalità di impostazione,
quella su linea di comando prevale sull’assegnazione
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
59 / 75
File di specifica
Opzioni & Debug
Debug del token manager
Il metodo CommonTokenAction() fornisce uno strumento utile al
debug: il trace dei token
mostra l’immagine di ogni token passato al parser per poter
controllare la corretta analisi lessicale
per far sì che il token manager non produca il trace:
ometterla dalla command line (per default è false), o
settare COMMON_TOKEN_ACTION a false, oppure
specificare -NOCOMMON_TOKEN_ACTION su command line
In alternativa, JavaCC fornisce info in modo automatico settando
l’opzione DEBUG_TOKEN_MANAGER
il token manager generato mostrerà moltissime info sul
processo di analisi lessicale
per il parsing c’è l’analoga opzione DEBUG_PARSER
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
60 / 75
File di specifica
Esempio
1
2
Opzioni & Debug
come il precedente, aggiungendo il main()
class RimCommenti {
public static void main(String args[]) {
3
4
5
6
7
if (args.length < 1) {
System.err.print("Nome file mancante!");
return 1;
}
8
9
10
11
12
13
14
15
16
17
// apertura stream file sorgente
java.io.inputStream in;
try {
in = new java.io.FileInputStream(args[0]);
} catch (java.io.FileNotFoundException e) {
System.err.println("File" + args[0] +
"non trovato");
return 1;
}
18
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
61 / 75
File di specifica
19
20
21
Opzioni & Debug
RimCommentiTokenMenager tm = new
RimCommentiTokenMenager(new
SimpleCharStream(in));
22
// loop lettura token
Token t = tm.getNextToken();
25
while (t.kind != RimCommentiConstants.EOF) {
26
System.out.println(t);
27
t = tm.getNextToken();
28
}
29
// stampa finale
30
System.out.println("\n N. commenti rimossi:"
31
+ tm.numCommenti);
32
} // mainstring
33 } // class
23
24
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
62 / 75
Argomenti Avanzati
Sommario
1
2
3
JavaCC
Installazione
Nozioni Preliminari
Espressioni Regolari Estese
Operatori
Insiemi di Caratteri
Denominazione dei token
File di specifica
Sezioni
N. Fanizzi
Linguaggi di prog.+Lab
4
5
File prodotti da JavaCC
Regole di match del token
manager
Azioni nel token manager
Opzioni & Debug
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole MORE
Esercizi
javacc – Analisi Lessicale
10 aprile 2014
63 / 75
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole SPECIAL_TOKEN I
L’espressione regolare SPECIAL_TOKEN descrive token speciali che
non hanno significato autonomo
I token speciali sono comunque passati al parser
precisamente vengono passati in congiunzione con i token
normali attraverso il campo specialToken di Token
il campo punta al token speciale immediatamente precedente
rispetto al token corrente (speciale o normale)
Se il token precedente è normale (non è uno speciale), allora il
campo è nullo.
I token speciali sono utili all’elaborazione di lessemi come i
commenti che non hanno significato per il parsing ma sono
significativi per il file in input
Si può accedere ad ogni token speciali usando azioni nella
specifica lessicale / sintattica
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
64 / 75
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole SPECIAL_TOKEN II
Esempio
SPECIAL_TOKEN:
{
3 <B: "b">
4|
5 <C: "c">
6}
7 TOKEN:
8{
9 <D: "d">
10 |
11 <E: "e">
12 }
1
2
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
65 / 75
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole SPECIAL_TOKEN III
Supponiamo di avere in input "dbce":
"d" viene identificato nel blocco TOKEN
l’oggetto relativo viene restituito al parser
"b" viene identificato come SPECIAL_TOKEN
si crea un token "b", ma non lo si restituisce
"c" viene identificato come SPECIAL_TOKEN
si crea un nuovo token e il campo specialToken lo concatena
al token speciale precedente
"e" viene identificato come TOKEN
si crea un token ("e") e lo si collega al token normale
precedente ("d") attraverso il campo next
si collega il token anche al precedente token speciale
attraverso il campo specialToken
il token viene quindi restituito al parser
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
66 / 75
Argomenti Avanzati
Regole MORE
Regole MORE I
A volte è utile costruire gradualmente un token da passare al
parser
La corrispondenza con questo tipo di espressioni regolari
viene salvata in un buffer fino alla corrispondenza con token
normali o speciali
Quindi tutte le corrispondenze nel buffer e i token normali o
speciali finali vengono concatenate per formare un unico
token normale o speciale che viene passato al parser
Se invece si incontra una corrispondenza con una regola di
SKIP il contenuto del buffer viene eliminato
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
67 / 75
Argomenti Avanzati
Regole MORE
Regole MORE II
Esempio
SKIP :
{
3
"/*" : IN_COMMENTO
4}
1
2
5
<IN_COMMENTO> SKIP :
{
8
"*/" : DEFAULT
9}
6
7
10
<IN_COMMENTO> MORE :
{
13
<~[]>
14 }
11
12
15
16
17
TOKEN_MGR_DECLS :
{
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
68 / 75
Argomenti Avanzati
Regole MORE
Regole MORE III
int lungStringa;
18
19
}
20
MORE :
{
23
"\"" { lungStringa = 0;} : IN_STRINGA
24 }
21
22
25
<IN_STRINGA> TOKEN :
{
28
<STRLIT: "\"">
29
{System.out.println("|S| = " + lungStringa);} : DEFAULT
30 }
26
27
31
<IN_STRINGA> MORE :
{
34
<~["\n","\r"]> {lungStringa++;}
35 }
32
33
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
69 / 75
Argomenti Avanzati
Regole MORE
Regole MORE IV
Esempio
stringhe con escape di doppi apici e backslash
SKIP:
{
3
...
4}
1
2
5
MORE :
{
8
"\"" : IN_STRINGA
9}
6
7
10
TOKEN:
{
13
...
14 }
11
12
15
16
17
<IN_STRINGA> MORE :
{
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
70 / 75
Argomenti Avanzati
Regole MORE
Regole MORE V
"\\\""
// backslash e doppi apici
| "\\\\"
// backslash due volte
20 | <~["\"","\n","\r"]> // tutto tranne " \n e \r
21 }
18
19
22
<IN_STRINGA> TOKEN:
{
25
<STRINGA: "\"" > : DEFAULT
26 }
23
24
// apici a fine stringa
27
<*>
TOKEN:
30 {
31
<ERROR: "~[]">
32 }
28
29
N. Fanizzi
Linguaggi di prog.+Lab
// tutti gli altri casi
javacc – Analisi Lessicale
10 aprile 2014
71 / 75
Esercizi
Sommario
1
2
3
JavaCC
Installazione
Nozioni Preliminari
Espressioni Regolari Estese
Operatori
Insiemi di Caratteri
Denominazione dei token
File di specifica
Sezioni
N. Fanizzi
Linguaggi di prog.+Lab
4
5
File prodotti da JavaCC
Regole di match del token
manager
Azioni nel token manager
Opzioni & Debug
Argomenti Avanzati
Regole SPECIAL_TOKEN
Regole MORE
Esercizi
javacc – Analisi Lessicale
10 aprile 2014
72 / 75
Esercizi
Esercizi I
1
Scrivere le espressioni regolari per il riconoscimento di
costanti intere in base ottale (prefisso O), decimale (senza
prefisso), esadecimale (prefisso ox).
Oltre al riconoscimento (per le non decimali) si può stampare
il valore.
[dal Galles]
2
Come il precedente ma usando suffissi del tipo x<base> con
<base> carattere tra 0 e 9 o tra A e Z.
Se la <base> è vuota il numero è decimale.
Es. 101x2 (binario) rappresenta il 5 in base decimale.
[dal Galles]
3
N. Fanizzi
Scrivere le specifiche di un riconoscitore di numeri interi in
cifre arabe che stampi/converta i numeri corrispondenti in
cifre romane.
[dal Galles]
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
73 / 75
Esercizi
Esercizi II
4
N. Fanizzi
Scrivere le specifiche di un riconoscitore di date gg/mm/aa
che le stampi/converta nel formato gg/mm/aaaa
con: aa < 50 → 19aa e aa ≥ 50 → 20aa.
[dal Galles]
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
74 / 75
Riferimenti
Riferimenti
D. Galles: Modern Compiler Design. Scott/Jones Publishing
A.J. Dos Reis: Compiler Construction Using Java, JavaCC, and
Yacc, Wiley-IEEE Computer Society Press
T. S. Norvell. Java Tutorial
N. Fanizzi: Manualetto JavaCC
N. Fanizzi
Linguaggi di prog.+Lab
javacc – Analisi Lessicale
10 aprile 2014
75 / 75