2009-08-24 14 views
8

Sto cercando di analizzare i CSS, o almeno le basi, usando ANTLR. Tuttavia, sto incontrando alcuni problemi con le mie regole di lexer. Il problema sta nell'ambiguità tra i selettori ID e i valori esadecimali dei colori. Utilizzando una grammatica semplificata per chiarezza, si consideri il seguente testo:Analisi CSS con ANTLR - edge case

#bbb { 
    color: #fff; 
} 

e le seguenti regole parser:

ruleset : selector '{' property* '}'; 
selector: '#' ALPHANUM; 
property: ALPHANUM ':' value ';' ; 
value: COLOR; 

e questi gettoni lexer:

ALPHANUM : ('a'..'z' | '0'..'9')+; 
COLOR : '#' ('0'..'9' | 'a'..'f')+; 

questo non funzionerà, perché #bbb è tokenizzato come token COLOR, anche se dovrebbe essere un selettore. Se cambio il selettore in modo che non inizi con un carattere esadecimale, funziona perfettamente. Non sono sicuro di come risolvere questo. C'è un modo per dire ad ANTLR di trattare un token specifico solo come token COLOR se si trova in una certa posizione? Supponiamo che, se si tratta di una regola di proprietà, posso tranquillamente pensare che si tratti di un token a colori. Se non lo è, trattalo come un selettore.

Qualsiasi aiuto sarebbe apprezzato!


Soluzione: Si scopre che stavo cercando di fare troppo nella grammatica, che dovrei probabilmente affrontare nel codice utilizzando l'AST. Il CSS ha troppi token ambigui per dividere in modo affidabile in diversi token, quindi l'approccio che sto usando ora sta fondamentalmente dando un token ai caratteri speciali come '#', '.', ':' E le parentesi graffe, e facendo post processing nel codice del consumatore. Funziona molto meglio ed è più facile gestire i casi limite.

risposta

8

Provare a spostare il # nel file lexer dal colore al proprio cosa, come ad esempio:

LLETTERS: ('a'..'z') 
ULETTERS: ('A'..'Z') 
NUMBERS: ('0'..'9') 
HASH : '#'; 

Poi, nelle regole del parser, si può fare in questo modo:

color: HASH (LLETTERS | ALPHANUM)+; 
selector: HASH (ULETTERS | LLETTERS) (ULETTERS | LLETTERS | NUMBERS)*; 

ecc.

Ciò consente di specificare la differenza grammaticalmente, che può essere approssimativamente descritta come contestualizzata, in senso lessicale, che può essere approssimativamente descritta come dall'aspetto. Se il significato di qualcosa cambia a seconda di dove si trova, quella differenza dovrebbe essere specificata nella grammatica, non nel lexer.

Nota che il colore e il selettore sono la stessa definizione. I lessici sono in genere una fase separata dal modulo che traduce la stringa di input in una grammatica, quindi non è valido avere un lessico ambiguo (come è stato sottolineato, bbb potrebbe essere esadecimale o potrebbe essere una stringa di lettere minuscole). Pertanto, il controllo della validità dei dati deve essere fatto altrove.

+0

Questo ancora non funziona. il problema è che bbb (o qualsiasi cosa che inizia con 0..9 | a..f) verrà tokenizzato come HEXSTRING. Ciò impedirà a #bbb di essere abbinato come selettore. –

+0

beh, in realtà ero indietro lì. Credo che dal momento che bbb sia una stringa valida E una stringa esadecimale valida, sarà necessario eseguire il controllo della validità dei dati sul lato software. –

+0

Questo è quello di cui ho paura. Speriamo che ci sia un guru del genere in giro qui su StackOverflow che può dimostrare che hai torto:/ –

2

Per Idem quello che ha detto Walt, Appendix G. Grammar of CSS 2.1 dice lex HASH, e poi (a seconda della sua posizione rispetto ad altri token) per analizzare un HASH sia come simple_selector o come hexcolor.

Il lexer definisce i seguenti token di ...

"#"{name}  {return HASH;} 

... e la grammatica include le seguenti regole ...

hexcolor 
    : HASH S* 
    ; 

simple_selector 
    : element_name [ HASH | class | attrib | pseudo ]* 
    | [ HASH | class | attrib | pseudo ]+ 
    ; 

Ciò significa che un parser basato sulla grammatica consentirebbe un colore esadecimale non esadecimale.

Individuerei un hexcolor non esadecimale più avanti, in codice che analizza/interpreta l'albero di sintassi lessato + parsed.

+0

Sì, ho familiarità con quell'appendice. È quello che uso come una delle mie fonti per la grammatica che sto costruendo. Non risolve il problema per me :( –

+0

@Erik: hai dato un'occhiata alla grammatica CSS disponibile su http://www.antlr.org/grammar/list –

+0

Sì, ho dato un'occhiata al Grammatica CSS 3, mostra lo stesso errore –

0

Per prendere una decisione da più alternative, ANTLR ha due opzioni,

  • predicati sintattici
  • predicati semantici

Questo è da ANTLR grammatica lib (CSS 2.1 g):

 
simpleSelector 
    : elementName 
     ((esPred)=>elementSubsequent)* 

    | ((esPred)=>elementSubsequent)+ 
    ; 

esPred 
    : HASH | DOT | LBRACKET | COLON 
    ; 

elementSubsequent 
    : HASH 
    | cssClass 
    | attrib 
    | pseudo 
    ; 

cssClass 
    : DOT IDENT 
    ; 

elementName 
    : IDENT 
    | STAR 
    ; 

Questo è utilizzato per predicati sintattici.

link di grammatica: http://www.antlr.org/grammar/1240941192304/css21.g

0

Proprio venuto qui da googling, e ha trovato una buona risorsa, un vero e proprio implimentation. Per coloro che vengono e cercano una grammatica CSS Antlr completa, dai un'occhiata al file di grammatica this. Questo può darti un'idea o puoi usarla direttamente.