すべての実装がサポートする必要がある最小のCSS(つまり,CSSの任意の版に含まれる。)の文法は, 7で定義する。 次の文法は,CSS1構文を定義するより小さな言語を定義する。
しかし,これはある意味では,CSS1の上位集合ともなる。つまり,この文法には表現されない付加的な意味制約が存在する。 適合するUAは,上位互換の構文解析規則(7.1),特性及び値の記法(5)並びに単位の記法(6)をも守らなければならない。 さらに,HTMLは,例えばCLASS属性の可能な値についての制約を課す。
次の文法は,LL(1)を示す。(しかし,多くのUAは,直接これを使わなくともよい。 これは構文解析規約を示すものではなく,CSS1の構文だけを示す。) 生成規則のフォーマットは,人が用いるために最適化され,yacc[15] では扱えない幾つかの簡略表記を用いる。
* : 0以上 + : 1以上 ? : 0 又は 1 | : 選択対象を分離 [] : グループ化
生成規則は次のとおり。
stylesheet : [CDO|CDC]* [ import [CDO|CDC]* ]* [ ruleset [CDO|CDC]* ]* ; import : IMPORT_SYM [STRING|URL] ';' /* E.g., @import url(fun.css); */ ; unary_operator : '-' | '+' ; operator : '/' | ',' | /* empty */ ; property : IDENT ; ruleset : selector [ ',' selector ]* '{' declaration [ ';' declaration ]* '}' ; selector : simple_selector+ [ pseudo_element | solitary_pseudo_element ]? | solitary_pseudo_element ; /* An "id" is an ID that is attached to an element type ** on its left, as in: P#p007 ** A "solitary_id" is an ID that is not so attached, ** as in: #p007 ** Analogously for classes and pseudo-classes. */ simple_selector : element_name id? class? pseudo_class? /* eg: H1.subject */ | solitary_id class? pseudo_class? /* eg: #xyz33 */ | solitary_class pseudo_class? /* eg: .author */ | solitary_pseudo_class /* eg: :link */ ; element_name : IDENT ; pseudo_class /* as in: A:link */ : LINK_PSCLASS_AFTER_IDENT | VISITED_PSCLASS_AFTER_IDENT | ACTIVE_PSCLASS_AFTER_IDENT ; solitary_pseudo_class /* as in: :link */ : LINK_PSCLASS | VISITED_PSCLASS | ACTIVE_PSCLASS ; class /* as in: P.note */ : CLASS_AFTER_IDENT ; solitary_class /* as in: .note */ : CLASS ; pseudo_element /* as in: P:first-line */ : FIRST_LETTER_AFTER_IDENT | FIRST_LINE_AFTER_IDENT ; solitary_pseudo_element /* as in: :first-line */ : FIRST_LETTER | FIRST_LINE ; /* There is a constraint on the id and solitary_id that the ** part after the "#" must be a valid HTML ID value; ** e.g., "#x77" is OK, but "#77" is not. */ id : HASH_AFTER_IDENT ; solitary_id : HASH ; declaration : property ':' expr prio? | /* empty */ /* Prevents syntax errors... */ ; prio : IMPORTANT_SYM /* !important */ ; expr : term [ operator term ]* ; term : unary_operator? [ NUMBER | STRING | PERCENTAGE | LENGTH | EMS | EXS | IDENT | hexcolor | URL | RGB ] ; /* 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 | HASH_AFTER_IDENT ;
次にトークン化子を示す。flex[16]記法で記述する。 これは,flexの8ビット実装を仮定していることに注意。トークン化子は,大文字及び小文字を区別しない (flexコマンドラインオプションでは,-iに相当する。)。
unicode ¥¥[0-9a-f]{1,4} latin1 [¡-ÿ] escape {unicode}|¥¥[ -~¡-ÿ] stringchar {escape}|{latin1}|[ !#$%&(-~] nmstrt [a-z]|{latin1}|{escape} nmchar [-a-z0-9]|{latin1}|{escape} ident {nmstrt}{nmchar}* name {nmchar}+ d [0-9] notnm [^-a-z0-9¥¥]|{latin1} w [ ¥t¥n]* num {d}+|{d}*¥.{d}+ string ¥"({stringchar}|¥')*¥"|¥'({stringchar}|¥")*¥' %x COMMENT %s AFTER_IDENT %% "/*" {BEGIN(COMMENT);} <COMMENT>"*/" {BEGIN(0);} <COMMENT>¥n {/* ignore */} <COMMENT>. {/* ignore */} @import {BEGIN(0); return IMPORT_SYM;} "!"{w}important {BEGIN(0); return IMPORTANT_SYM;} {ident} {BEGIN(AFTER_IDENT); return IDENT;} {string} {BEGIN(0); return STRING;} {num} {BEGIN(0); return NUMBER;} {num}"%" {BEGIN(0); return PERCENTAGE;} {num}pt/{notnm} {BEGIN(0); return LENGTH;} {num}mm/{notnm} {BEGIN(0); return LENGTH;} {num}cm/{notnm} {BEGIN(0); return LENGTH;} {num}pc/{notnm} {BEGIN(0); return LENGTH;} {num}in/{notnm} {BEGIN(0); return LENGTH;} {num}px/{notnm} {BEGIN(0); return LENGTH;} {num}em/{notnm} {BEGIN(0); return EMS;} {num}ex/{notnm} {BEGIN(0); return EXS;} <AFTER_IDENT>":"link {return LINK_PSCLASS_AFTER_IDENT;} <AFTER_IDENT>":"visited {return VISITED_PSCLASS_AFTER_IDENT;} <AFTER_IDENT>":"active {return ACTIVE_PSCLASS_AFTER_IDENT;} <AFTER_IDENT>":"first-line {return FIRST_LINE_AFTER_IDENT;} <AFTER_IDENT>":"first-letter {return FIRST_LETTER_AFTER_IDENT;} <AFTER_IDENT>"#"{name} {return HASH_AFTER_IDENT;} <AFTER_IDENT>"."{name} {return CLASS_AFTER_IDENT;} ":"link {BEGIN(AFTER_IDENT); return LINK_PSCLASS;} ":"visited {BEGIN(AFTER_IDENT); return VISITED_PSCLASS;} ":"active {BEGIN(AFTER_IDENT); return ACTIVE_PSCLASS;} ":"first-line {BEGIN(AFTER_IDENT); return FIRST_LINE;} ":"first-letter {BEGIN(AFTER_IDENT); return FIRST_LETTER;} "#"{name} {BEGIN(AFTER_IDENT); return HASH;} "."{name} {BEGIN(AFTER_IDENT); return CLASS;} url¥({w}{string}{w}¥) | url¥({w}([^ ¥n¥'¥")]|¥¥¥ |¥¥¥'|¥¥¥"|¥¥¥))+{w}¥) {BEGIN(0); return URL;} rgb¥({w}{num}%?{w}¥,{w}{num}%?{w}¥,{w}{num}%?{w}¥) {BEGIN(0); return RGB;} [-/+{};,#:] {BEGIN(0); return *yytext;} [ ¥t]+ {BEGIN(0); /* ignore whitespace */} ¥n {BEGIN(0); /* ignore whitespace */} ¥<¥!¥-¥- {BEGIN(0); return CDO;} ¥-¥-¥> {BEGIN(0); return CDC;} . {fprintf(stderr, "%d: Illegal character (%d)¥n", lineno, *yytext);}