📄 parser.y
字号:
CSSSelector *end = $$;
while( end->tagHistory )
end = end->tagHistory;
end->relation = $2;
end->tagHistory = $1;
if ( $2 == CSSSelector::Descendant ||
$2 == CSSSelector::Child ) {
CSSParser *p = static_cast<CSSParser *>(parser);
DOM::DocumentImpl *doc = p->document();
if ( doc )
doc->setUsesDescendantRules(true);
}
else if ($2 == CSSSelector::Sibling) {
CSSParser *p = static_cast<CSSParser *>(parser);
DOM::DocumentImpl *doc = p->document();
if (doc)
doc->setUsesSiblingRules(true);
}
} else {
delete $1;
}
}
| selector error {
delete $1;
$$ = 0;
}
;
namespace_selector:
/* empty */ { $$.string = 0; $$.length = 0; }
| '*' { static unsigned short star = '*'; $$.string = ☆ $$.length = 1; }
| IDENT { $$ = $1; }
;
simple_selector:
element_name maybe_space {
$$ = new CSSSelector();
$$->tag = $1;
}
| element_name specifier_list maybe_space {
$$ = $2;
if ( $$ )
$$->tag = $1;
}
| specifier_list maybe_space {
$$ = $1;
if ($$)
$$->tag = makeId(static_cast<CSSParser*>(parser)->defaultNamespace, anyLocalName);;
}
| namespace_selector '|' element_name maybe_space {
$$ = new CSSSelector();
$$->tag = $3;
CSSParser *p = static_cast<CSSParser *>(parser);
if (p->styleElement && p->styleElement->isCSSStyleSheet())
static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->tag, domString($1));
}
| namespace_selector '|' element_name specifier_list maybe_space {
$$ = $4;
if ($$) {
$$->tag = $3;
CSSParser *p = static_cast<CSSParser *>(parser);
if (p->styleElement && p->styleElement->isCSSStyleSheet())
static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->tag, domString($1));
}
}
| namespace_selector '|' specifier_list maybe_space {
$$ = $3;
if ($$) {
$$->tag = makeId(anyNamespace, anyLocalName);
CSSParser *p = static_cast<CSSParser *>(parser);
if (p->styleElement && p->styleElement->isCSSStyleSheet())
static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->tag, domString($1));
}
}
;
element_name:
IDENT {
CSSParser *p = static_cast<CSSParser *>(parser);
DOM::DocumentImpl *doc = p->document();
QString tag = qString($1);
if ( doc ) {
if (doc->isHTMLDocument())
tag = tag.lower();
const DOMString dtag(tag);
$$ = makeId(p->defaultNamespace, doc->tagId(0, dtag.implementation(), false));
} else {
$$ = makeId(p->defaultNamespace, khtml::getTagID(tag.lower().ascii(), tag.length()));
// this case should never happen - only when loading
// the default stylesheet - which must not contain unknown tags
// assert($$ != 0);
}
}
| '*' {
$$ = makeId(static_cast<CSSParser*>(parser)->defaultNamespace, anyLocalName);
}
;
specifier_list:
specifier {
$$ = $1;
}
| specifier_list specifier {
$$ = $1;
if ($$) {
CSSSelector *end = $1;
while( end->tagHistory )
end = end->tagHistory;
end->relation = CSSSelector::SubSelector;
end->tagHistory = $2;
}
}
| specifier_list error {
delete $1;
$$ = 0;
}
;
specifier:
HASH {
$$ = new CSSSelector();
$$->match = CSSSelector::Id;
$$->attr = ATTR_ID;
CSSParser *p = static_cast<CSSParser *>(parser);
if (!p->strict)
$1.lower();
$$->value = atomicString($1);
}
| class
| attrib
| pseudo
;
class:
'.' IDENT {
$$ = new CSSSelector();
$$->match = CSSSelector::Class;
$$->attr = ATTR_CLASS;
CSSParser *p = static_cast<CSSParser *>(parser);
if (!p->strict)
$2.lower();
$$->value = atomicString($2);
}
;
attrib_id:
IDENT maybe_space {
CSSParser *p = static_cast<CSSParser *>(parser);
DOM::DocumentImpl *doc = p->document();
QString attr = qString($1);
if ( doc ) {
if (doc->isHTMLDocument())
attr = attr.lower();
const DOMString dattr(attr);
$$ = doc->attrId(0, dattr.implementation(), false);
} else {
$$ = khtml::getAttrID(attr.lower().ascii(), attr.length());
// this case should never happen - only when loading
// the default stylesheet - which must not contain unknown attributes
assert($$ != 0);
}
}
;
attrib:
'[' maybe_space attrib_id ']' {
$$ = new CSSSelector();
$$->attr = $3;
$$->match = CSSSelector::Set;
}
| '[' maybe_space attrib_id match maybe_space ident_or_string maybe_space ']' {
$$ = new CSSSelector();
$$->attr = $3;
$$->match = (CSSSelector::Match)$4;
$$->value = atomicString($6);
}
| '[' maybe_space namespace_selector '|' attrib_id ']' {
$$ = new CSSSelector();
$$->attr = $5;
$$->match = CSSSelector::Set;
CSSParser *p = static_cast<CSSParser *>(parser);
if (p->styleElement && p->styleElement->isCSSStyleSheet())
static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->attr, domString($3));
}
| '[' maybe_space namespace_selector '|' attrib_id match maybe_space ident_or_string maybe_space ']' {
$$ = new CSSSelector();
$$->attr = $5;
$$->match = (CSSSelector::Match)$6;
$$->value = atomicString($8);
CSSParser *p = static_cast<CSSParser *>(parser);
if (p->styleElement && p->styleElement->isCSSStyleSheet())
static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->attr, domString($3));
}
;
match:
'=' {
$$ = CSSSelector::Exact;
}
| INCLUDES {
$$ = CSSSelector::List;
}
| DASHMATCH {
$$ = CSSSelector::Hyphen;
}
| BEGINSWITH {
$$ = CSSSelector::Begin;
}
| ENDSWITH {
$$ = CSSSelector::End;
}
| CONTAINS {
$$ = CSSSelector::Contain;
}
;
ident_or_string:
IDENT
| STRING
;
pseudo:
':' IDENT {
$$ = new CSSSelector();
$$->match = CSSSelector::Pseudo;
$2.lower();
$$->value = atomicString($2);
if ($$->value == "empty" || $$->value == "only-child" ||
$$->value == "first-child" || $$->value == "last-child") {
CSSParser *p = static_cast<CSSParser *>(parser);
DOM::DocumentImpl *doc = p->document();
if (doc)
doc->setUsesSiblingRules(true);
}
}
|
':' ':' IDENT {
$$ = new CSSSelector();
$$->match = CSSSelector::Pseudo;
$3.lower();
$$->value = atomicString($3);
}
| ':' FUNCTION maybe_space simple_selector maybe_space ')' {
$$ = new CSSSelector();
$$->match = CSSSelector::Pseudo;
$$->simpleSelector = $4;
$2.lower();
$$->value = atomicString($2);
}
;
declaration_list:
declaration {
$$ = $1;
}
| decl_list declaration {
$$ = $1;
if ( $2 )
$$ = $2;
}
| decl_list {
$$ = $1;
}
| error invalid_block_list error {
$$ = false;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipping bogus declaration" << endl;
#endif
}
| error {
$$ = false;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipping all declarations" << endl;
#endif
}
;
decl_list:
declaration ';' maybe_space {
$$ = $1;
}
| declaration invalid_block_list ';' maybe_space {
$$ = false;
}
| error ';' maybe_space {
$$ = false;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipping bogus declaration" << endl;
#endif
}
| error invalid_block_list error ';' maybe_space {
$$ = false;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipping bogus declaration" << endl;
#endif
}
| decl_list declaration ';' maybe_space {
$$ = $1;
if ( $2 )
$$ = $2;
}
| decl_list error ';' maybe_space {
$$ = $1;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipping bogus declaration" << endl;
#endif
}
| decl_list error invalid_block_list error ';' maybe_space {
$$ = $1;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipping bogus declaration" << endl;
#endif
}
;
declaration:
property ':' maybe_space expr prio {
$$ = false;
CSSParser *p = static_cast<CSSParser *>(parser);
if ( $1 && $4 ) {
p->valueList = $4;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << " got property: " << $1 <<
($5?" important":"")<< endl;
#endif
bool ok = p->parseValue( $1, $5 );
if ( ok )
$$ = ok;
#ifdef CSS_DEBUG
else
kdDebug( 6080 ) << " couldn't parse value!" << endl;
#endif
} else {
delete $4;
}
delete p->valueList;
p->valueList = 0;
}
|
property error {
$$ = false;
}
|
property ':' maybe_space error expr prio {
/* The default movable type template has letter-spacing: .none; Handle this by looking for
error tokens at the start of an expr, recover the expr and then treat as an error, cleaning
up and deleting the shifted expr. */
delete $5;
$$ = false;
}
|
prio {
/* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */
$$ = false;
}
|
property ':' maybe_space {
/* div { font-family: } Just reduce away this property with no value. */
$$ = false;
}
;
property:
IDENT maybe_space {
QString str = qString($1);
$$ = getPropertyID( str.lower().latin1(), str.length() );
}
;
prio:
IMPORTANT_SYM maybe_space { $$ = true; }
| /* empty */ { $$ = false; }
;
expr:
term {
$$ = new ValueList;
$$->addValue( $1 );
}
| expr operator term {
$$ = $1;
if ( $$ ) {
if ( $2 ) {
Value v;
v.id = 0;
v.unit = Value::Operator;
v.iValue = $2;
$$->addValue( v );
}
$$->addValue( $3 );
}
}
| expr error {
delete $1;
$$ = 0;
}
;
operator:
'/' maybe_space {
$$ = '/';
}
| ',' maybe_space {
$$ = ',';
}
| /* empty */ {
$$ = 0;
}
;
term:
unary_term { $$ = $1; }
| unary_operator unary_term { $$ = $2; $$.fValue *= $1; }
| STRING maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; }
| IDENT maybe_space {
QString str = qString( $1 );
$$.id = getValueID( str.lower().latin1(), str.length() );
$$.unit = CSSPrimitiveValue::CSS_IDENT;
$$.string = $1;
}
/* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */
| DIMEN maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION }
| unary_operator DIMEN maybe_space { $$.id = 0; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION }
| URI maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; }
| UNICODERANGE maybe_space { $$.id = 0; $$.iValue = 0; $$.unit = CSSPrimitiveValue::CSS_UNKNOWN;/* ### */ }
| hexcolor { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_RGBCOLOR; }
| '#' maybe_space { $$.id = 0; $$.string = ParseString(); $$.unit = CSSPrimitiveValue::CSS_RGBCOLOR; } /* Handle error case: "color: #;" */
/* ### according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
| function {
$$ = $1;
}
;
unary_term:
NUMBER maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
| PERCENTAGE maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; }
| PXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; }
| CMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; }
| MMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; }
| INS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; }
| PTS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; }
| PCS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; }
| DEGS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; }
| RADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; }
| GRADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; }
| MSECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; }
| SECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; }
| HERZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; }
| KHERZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; }
| EMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; }
| QEMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = Value::Q_EMS; }
| EXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; }
;
function:
FUNCTION maybe_space expr ')' maybe_space {
Function *f = new Function;
f->name = $1;
f->args = $3;
$$.id = 0;
$$.unit = Value::Function;
$$.function = f;
} |
FUNCTION maybe_space error {
Function *f = new Function;
f->name = $1;
f->args = 0;
$$.id = 0;
$$.unit = Value::Function;
$$.function = f;
}
;
/*
* 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 maybe_space { $$ = $1; }
;
/* error handling rules */
invalid_at:
'@' error invalid_block {
$$ = 0;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipped invalid @-rule" << endl;
#endif
}
| '@' error ';' {
$$ = 0;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipped invalid @-rule" << endl;
#endif
}
;
invalid_import:
import {
delete $1;
$$ = 0;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipped invalid import" << endl;
#endif
}
;
invalid_rule:
error invalid_block {
$$ = 0;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipped invalid rule" << endl;
#endif
}
/*
Seems like the two rules below are trying too much and violating
http://www.hixie.ch/tests/evil/mixed/csserrorhandling.html
| error ';' {
$$ = 0;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipped invalid rule" << endl;
#endif
}
| error '}' {
$$ = 0;
#ifdef CSS_DEBUG
kdDebug( 6080 ) << "skipped invalid rule" << endl;
#endif
}
*/
;
invalid_block:
'{' error invalid_block_list error '}'
| '{' error '}'
;
invalid_block_list:
invalid_block
| invalid_block_list error invalid_block
;
%%
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -