本附录是规范性的。
以下语法定义了CSS2的语法。然而在某种情况下,作为本规范的CSS2的一个超集施加了本语法中没有表述的额外的语意约束。遵守规则的UA必须也同时遵照向下兼容的解析规则,属性及值说明以及单位说明。另外,文档语种可能施加约束。例如HTML增加了"class"属性的可能取值的约束。
以下的语法是LL(1)(但是注意,大多数UA不应该直接使用它,因为它并不说明解析约定,而只是CSS2语法)。最终产品的格式会对使用进行优化,而某些Yacc(参见[YACC])之外的快捷符号会被使用:
最终的产品是:
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* ; selector : 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* ; /* * There is a constraint on the color that it must * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F]) * after the "#"; e.g., "#000" is OK, but "#abcd" is not. */ hexcolor : HASH S* ;
下面的是词汇分析器,以Flex(参见[FLEX])语法写成。词汇分析器对大小写不敏感。
出现了两次"\377",代表了当前版本的Flex可以处理的最高序字符数(十进制的255)。它们应该被认为是"\4177777"(十进制1114111),这也是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;}
CSS1建议([CSS1])和我们上面讨论的在语法方面还有一些不同。大部分是因为CSS2中有而CSS1中没有的新增词汇。另外一些是因为语法经过了改写以便更易阅读。但是,还有一些不兼容的改变,因为CSS1语法中本来是错误的。具体解释如下。