本附录是规范性的。
以下语法定义了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语法中本来是错误的。具体解释如下。