Analisi Lessicale - LACAM - Università degli Studi di Bari

Analisi Lessicale
Nicola Fanizzi
Corso di Linguaggi di Programmazione
Dipartimento di Informatica
Università degli Studi di Bari
1 aprile 2014
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
1 / 37
Sommario
1
Analizzatore Lessicale
Introduzione
Funzionalità
2
Progetto di uno Scanner
Definizione delle categorie
Attributi dei token
Estensioni delle espressioni regolari
Errori Lessicali
Recupero delle situazioni d’errore
3
Implementazione
Codifica
Funzione scanner
Analisi lessicale ed automi
Azioni
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
2 / 37
Analizzatore Lessicale
Sommario
1
Analizzatore Lessicale
Introduzione
Funzionalità
2
Progetto di uno Scanner
Definizione delle categorie
Attributi dei token
Estensioni delle espressioni regolari
Errori Lessicali
Recupero delle situazioni d’errore
3
Implementazione
Codifica
Funzione scanner
Analisi lessicale ed automi
Azioni
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
3 / 37
Analizzatore Lessicale
Introduzione
Analisi Lessicale I
L’analisi lessicale è l’attività del compilatore tesa ad aggregare i
caratteri di un programma sorgente per
riconoscere e classificare
le stringhe appartenenti al vocabolario (o lessico)
del linguaggio di programmazione
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
4 / 37
Analizzatore Lessicale
Introduzione
Analisi Lessicale II
L’analizzatore lessicale (o scanner, lexer) è generalmente
realizzato come sottoprogramma del compilatore
su chiamata dell’analizzatore sintattico
lettura flusso di caratteri fino ad identificare una stringa
corrispondente ad una categoria del linguaggio di prog.
chiamata
(controllo)
sorgente
analizzatore
txt
lessicale
caratteri
token
analizzatore
sintattico
albero di
derivazione
resto
del
compilatore
tabella
dei
simboli
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
5 / 37
Analizzatore Lessicale
Introduzione
Analisi Lessicale III
terminologia
token: categoria lessicale (insieme di stringhe)
saranno i terminali per la sintassi
Esempio IF, ID, OP_REL
pattern = regole (produzioni o ER) per la costruzione dei
token
Esempi
IF = "if";
ID = LETTERA (CIFRA + LETTERA)*;
OP_REL = "<", ">", ">=", "<="
lessema: stringa che corrisponde a un pattern (per un token)
Esempio "if", "P123", "<"
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
6 / 37
Analizzatore Lessicale
Funzionalità
Funzionalità
Funzioni dello scanner:
riconoscimento di pattern corrispondenti alle categorie
parole chiave
identificatori
numeri
separatori ed operatori
stringhe
..
.
eliminazione spazi superflui, commenti e caratteri di
controllo
produzione listati del sorgente con gli eventuali errori
espansione delle macro (se previste dal linguaggio)
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
7 / 37
Progetto di uno Scanner
Sommario
1
Analizzatore Lessicale
Introduzione
Funzionalità
2
Progetto di uno Scanner
Definizione delle categorie
Attributi dei token
Estensioni delle espressioni regolari
Errori Lessicali
Recupero delle situazioni d’errore
3
Implementazione
Codifica
Funzione scanner
Analisi lessicale ed automi
Azioni
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
8 / 37
Progetto di uno Scanner
Definizione delle categorie
Definizione delle categorie I
Linguaggio Pascal-like
parole chiave: program, procedure, begin, end, . . .
identificatori: somma_parziale, h1, . . .
(lunghezza max: 15 caratteri)
separatori ed operatori a singolo carattere: + - ; : . . .
operatori a due caratteri: :=, <=, . . .
numeri interi positivi: es. 223472, . . .
stringhe: es. ’ciao, mondo!’, . . .
commenti: { ecco un commento }
Spazi e terminatori di linea servono a separare i vari simboli del
linguaggio
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
9 / 37
Progetto di uno Scanner
Definizione delle categorie
Definizione delle categorie II
Linguaggio Java-like
parole chiave: class, try, new, . . .
identificatori: sommaParziale, h1, . . .
(lunghezza max: 32 caratteri)
separatori ed operatori a singolo carattere: , + - ; = . . .
operatori a due caratteri: [ ], <=, . . .
numeri interi positivi: es. 223472, . . .
stringhe: es. "ciao, mondo!", . . .
commenti: /* questo e’ un commento */, . . .
Spazi e terminatori di linea servono a separare i vari simboli del
linguaggio
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
10 / 37
Progetto di uno Scanner
Attributi dei token
Attributi dei token I
Quando più di un pattern corrisponde ad un lessema lo scanner
deve fornire l’info associata
A tale scopo, lo scanner fornisce attributi associati ai token
i token influenzano il parsing
gli attributi servono alla traduzione dei token
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
11 / 37
Progetto di uno Scanner
Attributi dei token
Attributi dei token II
Esempio (attributi dei token)
Data la riga:
E = M * C ** 2
risultano le coppie seguenti:
(ID, p(E)), (ASS, ·), (ID, p(M)), (MUL, ·), (ID, p(C)), (POW, ·), (NUMINT, 2)
p(·) puntatore al record nella tavola dei simboli
NB: alcune coppie non hanno bisogno di attributo
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
12 / 37
Progetto di uno Scanner
Attributi dei token
Lessico I
Il lessico può essere descritto mediante espressioni regolari
sull’alfabeto dei caratteri ammessi:
KEYWORD = class + public + int + static + . . .
LETTERA = ’A’ + . . . + ’Z’ + ’a’ + . . . + ’z’
CIFRA = ’0’ + ’1’ + ’2’ + ’3’ + ’4’ + ’5’ + ’6’ + ’7’ + ’8’ +
’9’
ID = LETTERA(CIFRA+LETTERA)*
OP1 = ’!’ + ’=’ + . . .
OP2 = ’==’ + ’!=’ + ’<=’ + . . .
NUM = ( CIFRA )+
CAR_STAMP = insieme dei caratteri stampabili
CAR_STR = CAR_STAMP \ { " }
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
13 / 37
Progetto di uno Scanner
Attributi dei token
Lessico II
CAR_COMM = CAR_STAMP \ { * }
..
.
STRINGA = " (CAR_STR)* "
COMMENTO = ’/’’*’ (CAR_COMM + EoLn)* ’*’’/’
SPAZIATURA = ( ’ ’ + ’\t’ + EoLn )
SIMBOLO = KEYWORD + ID + OP1 + OP2 + NUM + STRINGA
SORGENTE = (SIMBOLO + COMMENTO + SPAZIATURA)* EoF
L’espressione SORGENTE descrive l’intero codice sorgente di un
programma
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
14 / 37
Progetto di uno Scanner
Estensioni delle espressioni regolari
Estensioni delle espressioni regolari
I sistemi automatici estendono gli operatori con abbreviazioni:
Estensioni
| in genere sostituisce il + delle ER
(...)? opzionalità (zero o uno): (R)? ≡ R|
(...)+ iterazione (uno o più): (R)+ ≡ R(R)*
[c1-c2] ins. di caratteri: un carattere tra c1+. . . +c2
es. [’a’-’z’] può indicare un caratteri tra ’a’ e ’z’
Esempio
CIFRA
INTERO
FRAZIONE
EXP
NUM_REALE
=
=
=
=
=
[’0’-’9’]
(CIFRA)+
(’.’INTERO)?
(’E’(’+’|’-’)? INTERO )?
INTERO FRAZIONE EXP
approfonditi in JavaCC
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
15 / 37
Progetto di uno Scanner
Errori Lessicali
Errori Lessicali I
codice
1
2
3
4
5
..
.
N. Fanizzi
Linguaggi di prog.+Lab
messaggio di errore
identificatore troppo lungo
numero intero troppo grande
fine linea inattesa
fine file inattesa
carattere non ammesso
..
.
Analisi Lessicale
1 aprile 2014
16 / 37
Progetto di uno Scanner
Errori Lessicali
Errori Lessicali II
Dato che lo scanner ha una visione locale del sorgente
pochi errori individuabili a livello lessicale
Esempio
wile ( a < g(x))
Se, in un programma (C,Java), si incontra wile per la prima volta
nel contesto mostrato:
lo scanner non sa distinguere tra un errore di battitura d’una
keyword o il nome di una funzione (non dichiarata)
Restituirebbe un identificatore segnalerebbe un errore più avanti
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
17 / 37
Progetto di uno Scanner
Recupero delle situazioni d’errore
Recupero delle situazioni d’errore I
Quando lo scanner non può andare avanti perché nessun pattern
corrisponde ai prefissi dell’input rimanente si ricorre ad azioni di
recupero
Panic Mode
Si cancellano i caratteri successivi fino a quando
non si ritrovi il pattern corrispondente ad un
token valido
Osservazioni
può confondere il parser
va bene in modalità interattive
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
18 / 37
Progetto di uno Scanner
Recupero delle situazioni d’errore
Recupero delle situazioni d’errore II
Altre azioni di recupero:
1
cancellazione di caratteri estranei al set ammesso
2
tentativo di inserimento di caratteri mancanti
3
rimpiazzo di caratteri non corretti con quelli giusti
4
scambio di caratteri adiacenti
In genere si prova la sequenza minima di trasformazioni per
riportare il programma in forma sintatticamente analizzabile
Crierio della minima distanza
Un programma errato ha k errori se
la sequenza più corta di trasformazioni
che lo porti a diventare un programma
valido ha lunghezza k
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
19 / 37
Implementazione
Sommario
1
Analizzatore Lessicale
Introduzione
Funzionalità
2
Progetto di uno Scanner
Definizione delle categorie
Attributi dei token
Estensioni delle espressioni regolari
Errori Lessicali
Recupero delle situazioni d’errore
3
Implementazione
Codifica
Funzione scanner
Analisi lessicale ed automi
Azioni
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
20 / 37
Implementazione
Codifica
Strutture Dati
Tipi strutturati per descrivere i token
Sintassi C-like
union Val_Codice {
char nome_id[16];
3
int val_int;
4
char buffer_str[81];
5}
1
2
6
struct Token {
int codice;
9
union Val_Codice val;
10
int col;
11 }
7
8
Come definire una classe Token in Java ?
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
21 / 37
Implementazione
Codifica
Codifica
cost. mnemonica
I_C
N_C
S_C
EOF_C
..
.
cost. numerica
1
2
3
4
..
.
significato
identificatore
intero
stringa
fine file
..
.
PROGRAM_C
CLASS_C
..
.
11
12
..
.
keyword PROGRAM
keyword CLASS
..
.
PLUS_C
MINUS_C
..
.
51
52
..
.
operatore +
operatore ..
.
ASSIGN_C
GE_C
...
71
72
...
operatore :=
operatore >=
...
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
22 / 37
Implementazione
Funzione scanner
Implementazione dello scanner
come funzione:
Token SCAN(void)
oppure come procedura:
SCAN(Token SYMBOL)
Compiti:
costruire simboli del linguaggio di programmazione (categorie)
fornire l’informazione strutturata sul loro contenuto
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
23 / 37
Implementazione
Analisi lessicale ed automi
Analisi lessicale ed automi I
Gli automi a stati finiti trovano applicazione nell’analisi lessicale:
Sviluppo diretto degli analizzatori lessicali
Tool per la generazione automatica di analizzatori lessicali
(es.: Lex, Flex, JavaCC, ANTLR, ecc.)
Strumenti di elaborazione di testi (es.: awk, grep, ecc.)
per il riconoscimento dei pattern nel testo (espressioni
regolari)
Ad es., per il linguaggio precedente...
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
24 / 37
Implementazione
Analisi lessicale ed automi
Analisi lessicale ed automi II
CAR_COMM
ERR
SPAZIATURA
car. err.
A
EOLN
/
COM
DIV
/
EQ
NEQ
=
=
ASS
=
*
!
+
NOT
PLUS
>
GEQ
LEQ
S2
N. Fanizzi
=
=
"
GT
MIN
<
LETTERA
"
LT
S1
MUL
CIFRA
CAR_STR
Linguaggi di prog.+Lab
Analisi Lessicale
ID*
LETTERA
+CIFRA
NUM
CIFRA
1 aprile 2014
25 / 37
Implementazione
Analisi lessicale ed automi
Implementazione (pseudo-codice) I
1
2
/* variabili globali */
char ch;
3
/* costanti */
const int A_S=0, COM_S=1, I_S=2, NUM_S=3;
6 const int S1_S=4, GT_S=6, LT_S=7;
7 const int ...
4
5
8
/* analizzatore lessicale (incompleto) */
void scan(Token symbol) {
11
int stato=A_S, exit_flag=0, read_flag=1;
12
do
13
switch(stato) {
14
case A_S:
15
if (ch == ’/’) stato=DIV_S;
16
else if (ch == ’*’)
17
{ stato=MUL_S; exit_flag=1; }
9
10
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
26 / 37
Implementazione
Analisi lessicale ed automi
Implementazione (pseudo-codice) II
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
N. Fanizzi
else if (ch == ’+’)
{ stato=PLUS_S; exit_flag=1; }
else if (ch == ’*’)
{ stato=MUL_S; ; exit_flag=1; }
else if (ch == ’-’)
{ stato=MIN_S; exit_flag=1; }
else if (isalpha(ch)) stato=ID_S;
else if (isnum(ch)) stato=NUM_S;
else if (ch == ’=’) stato=ASS_S;
else if (ch == ’!’) stato=NOT_S;
else if (ch == ’>’) stato=GT_S;
else if (ch == ’<’) stato=LT_S;
else if (ch == ’"’) stato=S1_S;
else stato = ERR_S;
getnextchar(ch);
break;
case DIV_S:
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
27 / 37
Implementazione
Analisi lessicale ed automi
Implementazione (pseudo-codice) III
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
N. Fanizzi
if (ch == ’/’) stato = COM_S;
else { exit_flag=1; read_flag=1; }
case COM_S:
if (iscommentcar(ch)) getnextchar(ch);
else if (ch == ’\n’)
stato = A_S;
else if (ch == EOF)
{ stato=EOF_S; exit_flag=1; }
else error(COM_S);
break;
case I_S:
if (isalnum(ch)) getnextchar(ch);
else { exit_flag=1; read_flag=1; }
break;
case NUM_S:
if (isnum(ch)) getnextchar(ch);
else { exit_flag=1; read_flag=1; }
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
28 / 37
Implementazione
Analisi lessicale ed automi
Implementazione (pseudo-codice) IV
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
N. Fanizzi
break;
case ASS_S:
if (ch == ’=’) stato = EQ_S;
else { exit_flag=1; read_flag=1; }
break;
case EQ_S:
exit_flag=1;
break;
case NOT_S:
if (ch == ’=’) stato = NEQ_S;
else { exit_flag=1; read_flag=1; }
break;
case NEQ_S:
exit_flag=1;
break;
case S1_S:
if (isstrchar(ch)) getnextchar(ch);
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
29 / 37
Implementazione
Analisi lessicale ed automi
Implementazione (pseudo-codice) V
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
N. Fanizzi
else if (ch == ’"’) stato = S2_S;
else error(S1_S);
break;
case GT_S:
if (ch == ’=’) stato = GEQ_S;
else { exit_flag=1; read_flag=1; }
break;
case GEQ_S:
exit_flag=1;
break;
case LT_S:
if (ch == ’=’) stato = NEQ_S;
else { exit_flag=1; read_flag=1; }
break;
case LEQ_S:
exit_flag=1;
break;
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
30 / 37
Implementazione
Analisi lessicale ed automi
Implementazione (pseudo-codice) VI
86
87
default: error() /* stato inatteso */
} /* switch */
88
if (!read_flag)
getnextchar(ch);
91
} while(!exit_flag);
92 return token(stato);
93 } /* scan */
89
90
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
31 / 37
Implementazione
Analisi lessicale ed automi
Routine di servizio
In C, invece delle switch con molti rami, si possono usare
if in cascata e test implementati mediante funzioni di libreria
isalnum(), isalpha(), isdigit(), . . .
procedura
readch(char *ch,int *ch_col)
restituisce in ch il prossimo carattere e
restituisce in ch_col la sua posizione nella linea corrente
occorre anche una procedura di inizializzazione
init_scan(Token *SYMBOL)
apre il file sorgente,
inizializza la tabella delle parole chiave
legge il primo carattere chiamando readch()
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
32 / 37
Implementazione
Azioni
Azioni I
Codice da eseguire secondo l’evoluzione dell lavoro di analisi
az. iniziale associato allo stato di partenza
es. A ` ID il primo carattere dell’identificatore viene
copiato (contenuto in ch) in un array SYMBOL_name[0]
az. associata ad arco codice eseguito quando si transita sull’arco
es. ID ` ID la lettera o la cifra in ch viene aggiunta alla
stringa SYMBOL_name;
se si è raggiunto il limite si segnala l’errore
az. finali associate ad uno stato finale con archi uscenti, es. ID
se c’è stato errore lo si segnala
altrimenti si cerca nella tabella delle parole-chiave
la categoria sintattica corrispondente sarà identificatore
oppure quella della keyword trovata
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
33 / 37
Implementazione
Azioni
Azioni II
void scan(Token *SYMBOL) {
int s=A_S; int exit_flag=0, read_flag=1;
3 do
4
switch(s) {
5
case A_S:
6
switch(ch) {
7
case ’A’:
8
...
9
case ’Z’:
10
SYMBOL->col=ch_col;
11
i=1;
12
SYMBOL->name[0]=ch;
13
s=I_S;
14
break;
15
} /* switch interno A_S*/
1
2
16
17
N. Fanizzi
...
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
34 / 37
Implementazione
Azioni
Azioni III
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
N. Fanizzi
case I_S:
switch(ch) {
case ’0’:
...
case ’9’:
case ’A’:
...
case ’Z’:
if (i<I_LENGTH)
{i++; SYMBOL->name[i-1]=ch;}
else
error_flag=1;
default:
if (error_flag)
error(1,SYMBOL->col);
for( ; i<I_LENGTH ; i++)
SYMBOL->name[i-1]=’ ’;
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
35 / 37
Implementazione
Azioni
Azioni IV
if (is_keyword(SYMBOL->name,key))
SYMBOL->code=key;
else
SYMBOL->code=I_C;
} /* switch interno I_S */
35
36
37
38
39
40
...
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
36 / 37
Bibliografia
Fonti
Aho, Lam, Sethi, Ullman: Compilatori - Principi, tecniche e
strumenti. 2a ed., Pearson
Dos Reis: Compiler Construction Using Java, JavaCC, and Yacc.
Wiley-IEEE
Grune, Bal, Jacobs, Langendoen: Modern Compiler Design,
Wiley
N. Fanizzi
Linguaggi di prog.+Lab
Analisi Lessicale
1 aprile 2014
37 / 37