Appendice D. La grammatica dei CSS2

Sommario

Questa appendice è normativa.

La grammatica di cui sotto definisce la sintassi dei CSS2. Tuttavia si tratta, in un certo senso, di un super-insieme dei CSS2, poichè queste specifiche impongono restrizioni semantiche aggiuntive non espresse in questa grammatica. Un programma utente conforme deve anche aderire alle regole di analisi compatibili nel futuro, alla notazione di valore e proprietà, e alla notazione di unità. In aggiunta, il linguaggio del documento può imporre restrizioni, per esempio HTML impone restrizioni sui valori possibili dell'attributo "class".

D.1 Grammatica

La grammatica di cui sotto è LL(1) (ma si noti che la maggior parte dei programmi utente non dovrebbero usarla direttamente, poichè non esprime le convenzioni di analisi, ma solo la sintassi CSS2). Il formato delle produzioni è ottimizzato per la fruizione umana e sono usate alcune notazioni stenografiche oltre Yacc (si veda [YACC]):

Le produzioni sono:

stylesheet
  : [ CHARSET_SYM S* STRING S* ';' ]?
    [S|CDO|CDC]* [ import [S|CDO|CDC]* ]*
    [ [ ruleset | media | page | font_face ] [S|CDO|CDC]* ]*
  ;
import
  : IMPORT_SYM S*
    [STRING|URI] S* [ medium [ ',' S* medium]* ]? ';' S*
  ;
media
  : MEDIA_SYM S* medium [ ',' S* medium ]* '{' S* ruleset* '}' S*
  ;
medium
  : IDENT S*
  ;
page
  : PAGE_SYM S* IDENT? pseudo_page? S*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;
pseudo_page
  : ':' IDENT
  ;
font_face
  : FONT_FACE_SYM S*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;
operator
  : '/' S* | ',' S* | /* empty */
  ;
combinator
  : '+' S* | '>' S* | /* empty */
  ;
unary_operator
  : '-' | '+'
  ;
property
  : IDENT S*
  ;
ruleset
  : selector [ ',' S* selector ]*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;
selettore
  : simple_selector [ combinator simple_selector ]*
  ;
simple_selector
  : element_name? [ HASH | class | attrib | pseudo ]* S*
  ;
class
  : '.' IDENT
  ;
element_name
  : IDENT | '*'
  ;
attrib
  : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
    [ IDENT | STRING ] S* ]? ']'
  ;
pseudo
  : ':' [ IDENT | FUNCTION S* IDENT S* ')' ]
  ;
declaration
  : property ':' S* expr prio?
  | /* empty */
  ;
prio
  : IMPORTANT_SYM S*
  ;
expr
  : term [ operator term ]*
  ;
term
  : unary_operator?
    [ NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
      TIME S* | FREQ S* | function ]
  | STRING S* | IDENT S* | URI S* | RGB S* | UNICODERANGE S* | hexcolor
  ;
function
  : FUNCTION S* expr ')' S*
  ;
/*
 * Questa è una restrizione sul colore che deve
 * avere 3 o 6 cifre esadecimali (ossia, [0-9a-fA-F])
 * dopo "#"; per esempio, "#000" va bene, ma "#abcd" no.
 */
hexcolor
  : HASH S*
  ;

D.2 Analizzatore lessicale

Quello che segue è il tokenizzatore, scritto nella notazione Flex (si veda [FLEX]). Il tokenizzatore non è sensibile alle maiuscole e alle minuscole.

Le due ricorrenze di "\377" rappresentano il numero di carattere più alto che le versioni correnti di Flex possono gestire (decimale 255). Dovrebbero essere letti come "\4177777" (decimale 1114111), che è il più alto punto di codifica possibile in Unicode/, ISO-10646.

%option case-insensitive

h		[0-9a-f]
nonascii	[\200-\377]
unicode		\\{h}{1,6}[ \t\r\n\f]?
escape		{unicode}|\\[ -~\200-\377]
nmstart		[a-z]|{nonascii}|{escape}
nmchar		[a-z0-9-]|{nonascii}|{escape}
string1		\"([\t !#$%&(-~]|\\{nl}|\'|{nonascii}|{escape})*\"
string2		\'([\t !#$%&(-~]|\\{nl}|\"|{nonascii}|{escape})*\'

ident		{nmstart}{nmchar}*
name		{nmchar}+
num		[0-9]+|[0-9]*"."[0-9]+
string		{string1}|{string2}
url		([!#$%&*-~]|{nonascii}|{escape})*
w		[ \t\r\n\f]*
nl		\n|\r\n|\r|\f
range		\?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}(\?{0,3}|{h}(\?{0,2}|{h}(\??|{h})))))

%%

[ \t\r\n\f]+		{return S;}

\/\*[^*]*\*+([^/][^*]*\*+)*\/	/* ignore comments */

"<!--"			{return CDO;}
"-->"			{return CDC;}
"~="			{return INCLUDES;}
"|="			{return DASHMATCH;}

{string}		{return STRING;}

{ident}			{return IDENT;}

"#"{name}		{return HASH;}

"@import"		{return IMPORT_SYM;}
"@page"			{return PAGE_SYM;}
"@media"		{return MEDIA_SYM;}
"@font-face"		{return FONT_FACE_SYM;}
"@charset"		{return CHARSET_SYM;}
"@"{ident}		{return ATKEYWORD;}

"!{w}important"		{return IMPORTANT_SYM;}

{num}em			{return EMS;}
{num}ex			{return EXS;}
{num}px			{return LENGTH;}
{num}cm			{return LENGTH;}
{num}mm			{return LENGTH;}
{num}in			{return LENGTH;}
{num}pt			{return LENGTH;}
{num}pc			{return LENGTH;}
{num}deg		{return ANGLE;}
{num}rad		{return ANGLE;}
{num}grad		{return ANGLE;}
{num}ms			{return TIME;}
{num}s			{return TIME;}
{num}Hz			{return FREQ;}
{num}kHz		{return FREQ;}
{num}{ident}		{return DIMEN;}
{num}%			{return PERCENTAGE;}
{num}			{return NUMBER;}

"url("{w}{string}{w}")"	{return URI;}
"url("{w}{url}{w}")"	{return URI;}
{ident}"("		{return FUNCTION;}

U\+{range}		{return UNICODERANGE;}
U\+{h}{1,6}-{h}{1,6}	{return UNICODERANGE;}

.			{return *yytext;}

D.3 Comparazione tra le formalizzazioni di CSS2 e CSS1

[tokenization, formalizzazione o "tokenizzazione"] Ci sono alcune differenze nella sintassi specificata nella raccomandazione CSS1 ([CSS1]), e in quella di cui sopra. Molte di loro sono dovute ai nuovi token dei CSS2 che non esistevano nei CSS1. Altre invece sono dovute al fatto che la grammatica è stata riscritta per essere più leggibile. Tuttavia, vi sono alcune modifiche incompatibili, che vengono percepite come errori nella sintassi CSS1. Sono illustrate di seguito.