2009-08-24 19 views
8

Estoy tratando de analizar CSS, o al menos los conceptos básicos, utilizando ANTLR. Sin embargo, estoy teniendo algunos problemas con mis reglas de Lexer. El problema radica en la ambigüedad entre los selectores de ID y los valores de color hexadecimales. El uso de una gramática simplificada para mayor claridad, considere la siguiente entrada:Análisis CSS con ANTLR - casos extremos

#bbb { 
    color: #fff; 
} 

y las siguientes reglas del analizador:

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

y estas fichas lexer:

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

Esto no va a funcionar, porque #bbb se tokeniza como un token de COLOR, aunque se supone que es un selector. Si cambio el selector para que no comience con un carácter hexadecimal, funciona bien. No estoy seguro de cómo resolver esto. ¿Hay alguna manera de decirle a ANTLR que trate una ficha específica solo como una ficha de COLOR si está en una posición determinada? Digamos, si está en una regla de propiedad, puedo suponer con seguridad que es un token de color. Si no es así, trátalo como un selector.

¡Cualquier ayuda sería apreciada!


Solución: Resulta que yo estaba tratando de hacer demasiado en la gramática, lo que probablemente debería tratar en el código utilizando el AST. CSS tiene demasiados toques ambiguos para dividir de manera confiable en tokens diferentes, por lo que el enfoque que estoy usando ahora es básicamente tokenizar los caracteres especiales como '#', '.', ':' Y las llaves, y hacer el procesamiento posterior en el código de consumidor Funciona mucho mejor, y es más fácil lidiar con casos extremos.

Respuesta

8

Intente mover el # en el archivo de léxico de color a lo suyo, como tal:

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

Luego, en las reglas del analizador, puede hacerlo de esta manera:

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

etc.

Esto le permite especificar la diferencia gramaticalmente, que puede describirse aproximadamente como contextualmente, frente a léxico, lo que puede describirse aproximadamente como por apariencia. Si algo cambia de significado dependiendo de dónde se encuentre, esa diferencia debe especificarse en la gramática, no en el lexer.

Tenga en cuenta que el color y el selector son bastante parecidos. Los Lexers son típicamente una etapa separada del módulo que traduce la cadena de entrada a una gramática, por lo que no es válido tener un léxico ambiguo (como se señaló, bbb podría ser hexadecimal o podría ser una cadena de letras minúsculas). Por lo tanto, la verificación de la validez de los datos debe hacerse en otro lugar.

+0

Esto todavía no funciona. el problema es que bbb (o cualquier cosa que comience con 0..9 | a..f) se tokenizará como HEXSTRING. Esto evitará que #bbb coincida como un selector. –

+0

bueno, en realidad estaba al revés allí. Creo que dado que bbb es una cadena válida Y una cadena hexadecimal válida, necesitará hacer una verificación de validez de datos del lado del software. –

+0

Eso es lo que temo. Con suerte, hay un gurú antlr corriendo por stackoverflow que puede probar que estás equivocado:/ –

2

Para Ditto lo que dijo Walt Appendix G. Grammar of CSS 2.1, dice a la lex HASH, y luego (en función de su posición en relación con otra ficha) para analizar una HASH ya sea como simple_selector o como hexcolor.

El analizador léxico define el siguiente token ...

"#"{name}  {return HASH;} 

... y la gramática incluye las siguientes reglas ...

hexcolor 
    : HASH S* 
    ; 

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

Esto significa que un programa de análisis basado en la gramática permitiría una HexColor no hexagonal.

Detectaría un hexcolor no hexadecimal más tarde, en el código que analiza/interpreta el árbol de sintaxis analizado lexed +.

+0

Sí, estoy familiarizado con ese apéndice. Es lo que uso como una de mis fuentes para la gramática que estoy construyendo. Sin embargo, no resuelve el problema para mí :( –

+0

@Erik: ¿Has echado un vistazo a la gramática CSS disponible en http://www.antlr.org/grammar/list –

+0

Sí, he echado un vistazo a la Gramática de CSS 3, muestra el mismo error. –

0

Para tomar una decisión a partir de múltiples alternativas, antlr tiene dos opciones,

  • predicados sintácticos
  • predicados semánticos

Esto es de antlr lib gramática (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 
    ; 

Esto se utiliza para predicados sintácticos.

Enlace a la gramática: http://www.antlr.org/grammar/1240941192304/css21.g

0

Sólo vino aquí buscando en Google y encontró un buen recurso, un verdadero implimentation. Para aquellos que vienen y buscan una gramática CSS Antlr completa, entonces echen un vistazo al archivo de gramática this. Esto puede darte una idea o puedes usarla directamente.

Cuestiones relacionadas