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 🙂
grazie tante ale 6 un grande!!!!!il parser lo devo provare ma sono sicuro che funzionerà benissimo!!!! 🙂
E di che??
La conoscenza va condivisa 😉
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.;-)
Certamente. 🙂 Spero solo di trovarla altrimenti mi tocca ricavarmela 😉
La grammatica non l’ho trovata purtroppo e per motivi di tempo non riesco nemmeno a scrivertela tutta però ti insegno come si fa:
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..
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.
Scusami la stringa inserita era:
METAAPERTO name=\”prova\” METACHIUSO
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
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
Ciao Cristian puoi spiegarmi come dare in pasto a questo parser un testo formattato in html?
O come farlo funzionare da riga di comando ? purtroppo sono nuovo di javacc !
@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
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?
scusa la formattazione
@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 🙂
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 🙁
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
@Mimmo
Se mi mandi una mail con il .jj vedo di darci un’occhiata per capire l’errore.. 🙂
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!
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.. 😀