附属書 B(規定) CSS1 文法


すべての実装がサポートする必要がある最小の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);}