ePrometeusCorsoJavaJava
testi articoli
Testi Articoli  Download
Home | Eshop | Java | Tools | Web | 
CorsoJava è ora Video! Free for all!
Clicca Qui!

PARSER IN JAVA
Sviluppare parser in Java
Generatori di Parser
Grammatiche
Alberi Sintattici
Classe AST
Annotazione della grammatica
Valutazione dell'albero sintattico
Conclusioni
Bibliografia
L'Autore

<<< Grammatiche >>>

Il JavaCup (e il JavaCC) utilizzano una grammatica per descrivere il linguaggio di programmazione che devono analizzare. Le grammatiche possono essere definite, in maniera un po' pomposa, come "un formalismo per descrivere tutti i programmi esprimibili in un dato linguaggio". Più semplicemente con una grammatica serve a verificare se una certa stringa è un costrutto sintatticamente valido per il linguaggio da essa descritto. Poiché generalmente i costrutti esprimibili con una grammatica sono infiniti, la grammatica li può descrivere soltanto dando delle regole per generarli: sarebbe impensabile che li elencasse tutti. Per esempio:

	Grammatica 1
	(a) lang ::= LPAREN RPAREN
	(b) lang ::= LPAREN lang RPAREN

In questo caso abbiamo una grammatica che descrive tutte le stringhe che cominciano con n parentesi tonde aperte e finiscono con altrettante parentesi tonde chiuse. In questa notazione abbiamo due tipi di simboli: i terminali, come LPAREN e RPAREN , e i non-terminali (come lang); le regole, come (a) e (b), si dicono produzioni. I terminali sono simboli “definitivi”, cioè se compaiono non possono essere più rimpiazzati; i non-terminale possono invece essere rimpiazzati dal corpo di una regola che ha quel non-terminale in testa. In pratica un parser analizza il testo; quando incontra una "(" produce un simbolo LPAREN, quando incontra un ")" produce RPAREN.

Vediamo di capire come si usano le regole di una grammatica. Per verificare se un costrutto appartiene al linguaggio si verifica se si riesce a generarlo applicando le regole, a partire da un non-terminale che viene normalmente chiamato simbolo iniziale. Nel nostro caso il simbolo iniziale sarà necessariamente lang (non abbiamo molta scelta) e possiamo cominciare una generazione. La generazione (che potrebbe anche non terminare mai) termina quando nel programma generato non ci sono più simboli non terminali. Per esempio:

	     lang
(b)=>	LPAREN lang RPAREN
(a)=>	LPAREN LPAREN RPAREN RPAREN

Ovvero "(())"; quindi questa stringa fa parte del linguaggio generato dalla nostra grammatica. In pratica le grammatiche non vengono utilizzate in questo modo ma a ritroso: cioè dato un programma si cerca di stabilire se la grammatica è in grado di generare quel programma (il che vuol dire che il programma è grammaticalmente corretto) e, altrettanto importante, la sequenza di regole che hanno consentito di generare quel programma. I generatori di parser intercettano il riconoscimento delle regole, eseguendo delle operazioni al verificarsi del "matching" di una regola.

Un parser è un programma capace di verificare, a partire da una grammatica, se una stringa appartiene al linguaggio della grammatica, e soprattutto è in grado di riconoscere la sequenza di regole da applicare. Il problema teorico della costruzione del parser di una grammatica è stato studiato a fondo e ha prodotto strumenti automatici per la loro costruzione.

Questo problema comunque non è risolvibile nella sua formulazione più generale: non è possibile in generale riconoscere se un programma appartiene ad una grammatica per qualsiasi grammatica. È invece risolvibile solo per particolari grammatiche, con determinate limitazioni nel formato delle regole. La casistica è ampia e variegata, e non entreremo nei dettagli. Diciamo solo che sia Yacc che JavaCup sono generatori di parser per grammatiche di tipo LALR(1) non ambigua. Il primo genera codice C mentre il secondo genera codice Java.

ePrometeus s.r.l. - Web Software House & Open Source System Integrator
MILANO - SAN BENEDETTO DEL TRONTO(AP)
Contatti: info@eprometeus.com