Parser html con JavaCC

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 Risposte a “Parser html con JavaCC”

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

  2. 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.;-)

  3. 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..

  4. 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.

  5. Scusami la stringa inserita era:

    METAAPERTO name=\”prova\” METACHIUSO

  6. 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

  7. 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

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

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

  10. 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?

  11. @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 🙂

  12. 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 🙁

  13. 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!

  14. 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.. 😀

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

11 + 7 =

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.