Parser html con JavaCC

25 settembre 2009

Programmazione

Vi presento un piccolo esempio di come si può scrivere facilmente un parser LL1 in java con il tool JavaCC.
Il seguente codice è solo a scopo didattico, ovviamente non riconosce tutti i costrutti del linguaggio html ma rende l’ idea della semplicità di realizzazione di un parser.

options { IGNORE_CASE = true; } 
PARSER_BEGIN(parserHTML)
public class parserHTML {
		public static void main(String[] args)
		throws ParseException, TokenMgrError, java.io.FileNotFoundException{
			parserHTML parser = new parserHTML(new java.io.FileInputStream("input.txt"));
			parser.Start();
		}
	}
PARSER_END(parserHTML)
 
 
 
SKIP: {" "}
SKIP: {"\n" | "\r" | "\r\n" |"\t"}
SKIP: {"<!--": INCOMMENTO}
<INCOMMENTO>
SKIP:{"-->":DEFAULT | <~[]>}
TOKEN: {
		<PAGINAAPERTA: "<html>">
	|	<PAGINACHIUSA: "</html>">
	|	<TESTAAPERTA: "<head>">
	|	<TESTACHIUSA: "</head>">
	|	<TITOLOAPERTO: "<title>">
	|	<TITOLOCHIUSO: "</title>">
	|	<CORPOAPERTO: "<body>">
	|	<CORPOCHIUSO: "</body>">
	|	<FORMATTAZIONEAPERTA: "<b>">
	|	<FORMATTAZIONECHIUSA: "</b>">
	|	<PARAGRAFOAPERTO: "<p>">
	|	<PARAGRAFOCHIUSO: "</p>">
	|	<METAAPERTO: "<meta>">
	|	<CHIAVEMETA: "http-equiv">
	|	<METACHIUSO: "</meta>">
	|	<STILEAPERTO: "<style">
	|	<CHIAVESTILE: "text/css">
	|	<STILECHIUSO: "</style>">
	|	<COLLEGAMENTOAPERTO: "<a">
	|	<COLLEGAMENTOCHIUSO: "</a>">
	|	<INPUTAPERTO: "<input">
	|	<CHIAVE: "type" | "id" | "name">
	|	<CHIAVEINPUT: "checkbox" | "radio" | "submit">
	|	<CHIAVECOLLEGAMENTO: "href" | "title">
	|	<ACUTACHIUSA: ">">
	|	<NUOVALINEA: "<br>">
	|	<FORMAPERTO: "<form>">
	|	<FORMCHIUSO: "</form>">
	|	<UGUALE: "=">
	|	<VIRGOLETTE: "\"">
	|	<HAPERTA: "<h1>">
	|	<HCHIUSA: "</h1>">
	|	<TABELLAAPERTA: "<table>">
	|	<TABELLACHIUSA: "</table>">
	|	<RIGAAPERTA: "<tr>">
	|	<RIGACHIUSA: "</tr>">
	|	<CELLAAPERTA: "<td>">
	|	<CELLACHIUSA: "</td>">
	|	<CARATTERE: ["$","A"-"Z","_",",",".","a"-"z","0"-"9"]>
}
 
 
 
 
void Start():
{}
{
	<PAGINAAPERTA>
	testa()
	corpo()
	<PAGINACHIUSA>
	|
	{System.out.println("FILE VUOTO");}
}
 
 
void testa():
{}
{
	(
	<TESTAAPERTA>
	corpotesta()
	<TESTACHIUSA>
	)
	|
	{System.out.println("testa epsilon");}
}
 
void corpotesta():
{}
{
	(
		<TITOLOAPERTO>
		stringa()
		<TITOLOCHIUSO>
		corpotesta()
	)
	|
	(
		<METAAPERTO>
		<CHIAVEMETA>
		<UGUALE>
		<VIRGOLETTE>
		stringa()
		<VIRGOLETTE>
		<METACHIUSO>
		corpotesta()
	)
	|
	(
		<STILEAPERTO>
		<CHIAVE>
		<UGUALE>
		<VIRGOLETTE>
		<CHIAVESTILE>
		<VIRGOLETTE>
		<ACUTACHIUSA>
		stringa()
		<STILECHIUSO>
		corpotesta()
	)
	|	
	{System.out.println("corpotesta epsilon");}
}
 
void stringa():
{}
{
	(
		(<CARATTERE>)*
		(<NUOVALINEA>)*
	)
	|
	{System.out.println("stringa epsilon");}	
}
 
 
void corpo():
{}
{
	<CORPOAPERTO>
	contenuto()
	<CORPOCHIUSO>
	(<NUOVALINEA>)*
	|  	
	{System.out.println("corpo epsilon");}
 
}
 
 
void contenuto():
{}
{
	(	
		<HAPERTA>
		stringa()
		<HCHIUSA>
		contenuto()
	)	
	|
	(
		<PARAGRAFOAPERTO>
		contenuto()
		<PARAGRAFOCHIUSO>
		contenuto()
	)
	|
	(
		<COLLEGAMENTOAPERTO>
		(
			<CHIAVECOLLEGAMENTO>
			<UGUALE>
			<VIRGOLETTE>
			stringa()
			<VIRGOLETTE>
		)*
		<ACUTACHIUSA>
		stringa()
		<COLLEGAMENTOCHIUSO>
		contenuto()
	)
	|
	(
		<NUOVALINEA>
		contenuto()
	)
	|
	(
		<FORMAPERTO>
		contenuto()
		<FORMCHIUSO>
		contenuto()
	)
	|
	(
		<INPUTAPERTO>
		(
		<CHIAVE>
		<UGUALE>
		<VIRGOLETTE>
		<CHIAVEINPUT>
		<VIRGOLETTE>
		)+
		<ACUTACHIUSA>
		contenuto()
	)
	|
	(
	<CARATTERE>
	stringa()
	contenuto()
	)
	|
	(
	<FORMATTAZIONEAPERTA>
	stringa()
	<FORMATTAZIONECHIUSA>
	contenuto()
	)
	|
	(
		<TABELLAAPERTA>
		(
			<RIGAAPERTA>
			(
				<CELLAAPERTA>
				stringa()
				<CELLACHIUSA>
			)*
			<RIGACHIUSA>
		)*
		<TABELLACHIUSA>
		contenuto()
	)
	|
	{System.out.println("contenuto epsilon");} 
}
Se ti è stato utile il mio articolo, spendi un secondo del tuo tempo e dammi un +1, Google ed io ne saremmo felici 🙂 Grazie mille 🙂
,

20 Responses to “Parser html con JavaCC”

  1. furiaceca Says:

    grazie tante ale 6 un grande!!!!!il parser lo devo provare ma sono sicuro che funzionerà benissimo!!!! 🙂

  2. predator1987 Says:

    E di che??
    La conoscenza va condivisa 😉

  3. iHAL984 Says:

    Cia Alessandro, potresti farmi avere, se non ti dispiace e sempre che sia possibile, la grammatica che hai adottato per la scrittura del parser?

    Te ne sarei grato.
    Grazie.;-)

  4. predator1987 Says:

    Certamente. 🙂 Spero solo di trovarla altrimenti mi tocca ricavarmela 😉

  5. predator1987 Says:

    La grammatica non l’ho trovata purtroppo e per motivi di tempo non riesco nemmeno a scrivertela tutta però ti insegno come si fa:

    Grammatica HTML

    Il meccanismo è semplice, ogni funzione è una riga di quelle sopra.
    Poi prendi ogni funzione e vedi come è scritta, la riporti su ogni riga e trasformi i System.out in ∈ e se ci sono funzioni con uno * devi occuparti di richiamarla e andare in ∈ come fa la funzione stringa.

    Spero di esserti stato di aiuto..

  6. Cristian Grosso Says:

    Ciao Alessandro, mi potresti dire perchè non riesco a fargli capire al parser che deve leggere i doppi apici??

    in pratica inserendo la stringa da console:

    name= \”prova\”

    si lamenta così:

    Exception in thread “main” TokenMgrError: Lexical error at line 4, column 14. Encountered: “\\” (92), after : “”
    at HTMLParserTokenManager.getNextToken(HTMLParserTokenManager.java:2023)
    at HTMLParser.jj_consume_token(HTMLParser.java:403)
    at HTMLParser.Head_Content(HTMLParser.java:58)
    at HTMLParser.Head_Content(HTMLParser.java:52)
    at HTMLParser.Head(HTMLParser.java:33)
    at HTMLParser.Html_Document(HTMLParser.java:19)
    at HTMLParser.main(HTMLParser.java:7)

    ci sto sbattendo da ieri, dammi una mano per favore.

    L’errore si presenta anche nel tuo di parser.

    Grazie mille.

  7. Cristian Grosso Says:

    Scusami la stringa inserita era:

    METAAPERTO name=\”prova\” METACHIUSO

  8. predator1987 Says:

    Ciao Cristian,
    se ho capito bene il problema la soluzione sta nel instruire il parser a riconoscere i doppi apici inserendo nei token anche il doppi apice come un token a se stante e poi lo usi come tutti gli altri token esempio:

    METAAPERTO name= DOPPIOAPICE blablabla DOPPIOAPICE METACHIUSO

  9. Cristian Says:

    Questo problema non c’è visto che i DOPPIAPICI, come nel tuo parser, li ho già inseriti in un token a se stante, dandogli il valore : “\””.
    Il problema consiste nel fatto che quando tento di far riconoscere la sintassi del meta_tag, o ad esempio dello style_tag, il parser si lamenta con quell’errore postato su.
    Ora siccome tale errore si presenta anche nel tuo parser vorrei sapere come fare a fargli riconoscere questi dannati doppiapici
    Io gli do in pasto: meta name=\”prova\” stringa metachiuso e si lamenta xkè non riconosce il token.
    La regola l’ho messa uguale a quella del tuo parser.

    Fammi sapere.
    Grazie

  10. Mimmo Says:

    Ciao Cristian puoi spiegarmi come dare in pasto a questo parser un testo formattato in html?

  11. Mimmo Says:

    O come farlo funzionare da riga di comando ? purtroppo sono nuovo di javacc !

  12. predator1987 Says:

    @Mimmo

    Ciao Mimmo,

    ti giro un link con un bel manualetto di JavaCC visto chè sei nuovo di questo tool, spero ti sia utile 🙂

    http://lacam.di.uniba.it:8000/~nico/corsi/lingpro/materiale/manualetto-javacc.pdf

  13. Mimmo Says:

    si grazie ho già fatto 😉 cmq quando compilo con javacc il tuo file mi appaiono due warning nella sezione
    [code]
    void stringa():
    {}
    {
    (
    ()*
    ()*
    )
    |
    {System.out.println(“stringa epsilon”);}
    }
    [/code]
    i due warning sono dovuti al fatto che a runtime il parser sbaglierà di fronte a frase in cui avrebbe dovuto fare l’altra scelta, per aggirare questo problema bisogna istruire il parser ad utilizzare un lookahead(2) quindi quel pezzo di codice diventa :

    void stringa():
    {}
    {LOOKAHEAD(2)
    (
    (LOOKAHEAD(2))*
    (LOOKAHEAD(2))*
    )
    |
    {System.out.println(“stringa epsilon”);}
    }

    In questo modo javacc non si lamenta! 😉
    hai risolto il problema del meta?

  14. Mimmo Says:

    scusa la formattazione

  15. predator1987 Says:

    @Mimmo

    Grazie Mimmo,

    questo era un esempio veramente “giocattolo” di un parser e non avrei mai immaginato che potesse tornare utile a qualcuno 🙂 ..andrebbe rivisto ma il tempo per farlo non lo troverò mai forse 🙁

    Comunque il problema di Cristian l’abbiamo risolto tramite email facendomi mandare il suo codice sorgente, perchè tramite commenti era impossibile altrimenti 🙂

    Grazie ancora per la tua soluzione, se ti va di postare un articolo/parser migliore dimmelo così potresti migliorarlo per il futuro 🙂

  16. Mimmo Says:

    Quando terminerò le migliorie del tuo parser te lo invierò tramite mail : 🙂
    Per ora ho migliorato l’aspetto che già ho menzionato sopra, il codice meta per come l’hai scritto tu è nella forma http-equiv:”string ” in realtà ho visto ke dev’essere che ho implementato nel mio codice.

    Il codice per i link nel tuo parser è in una delle due forme :
    1) stringa
    2) stringa
    in realtà title dovrebbe andare insieme ad href! Como posso istruire il parser a fargli capire che il link può essere costruito come :
    1) stringa
    OPPURE
    2) stringa

    Non ci sono ancora riuscito 🙁

  17. Mimmo Says:

    Dato che ho problemi di editing nel codice ti ho uppato un file su megaupload dove ti spiego alcune cose che serviranno a migliorare il parser 🙂
    http://www.megaupload.com/?d=T31I8FVE

  18. predator1987 Says:

    @Mimmo

    Se mi mandi una mail con il .jj vedo di darci un’occhiata per capire l’errore.. 🙂

  19. Pab Says:

    Scusatemi sto cercando di studiare i parser e ho incontrato questo esempio,
    ecco aldilà della sintassi utilizzata e le varie regole, quello che proprio non capisco è : A che serve ? Mi potresti far vedere, dopo aver scritto tutto questo, qual è l’effetto ? Alle volte le cose più semplici risultano essere le più incomprensibili 😛 Grazie!

  20. Alessandro Musacchio Says:

    Ciao Pab 😉
    Allora questo codice serve a validare un codice HTML, ovviamente non tutto il linguaggio, ma solo un sottoinsieme di esso, in quanto è a solo scopo didattico 😉
    L’effetto è che lanciato con JavaCC su un file html ti restituisce se quel documento è valido, ovvero se il documento segue la grammatica che noi abbiamo dato in pasto a JavaCC editando il codice di cui sopra 😉
    Spero di esser stato chiaro.. 😀

Leave a Reply

*