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