1 %{ 2 3 /* 4 * Copyright (C) 2002-2003 Lars Knoll (knoll (at) kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 6 * Copyright (C) 2006 Alexey Proskuryakov (ap (at) nypop.com) 7 * Copyright (C) 2008 Eric Seidel <eric (at) webkit.org> 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25 #include "config.h" 26 27 #include "CSSMediaRule.h" 28 #include "CSSParser.h" 29 #include "CSSPrimitiveValue.h" 30 #include "CSSPropertyNames.h" 31 #include "CSSRuleList.h" 32 #include "CSSSelector.h" 33 #include "CSSStyleSheet.h" 34 #include "Document.h" 35 #include "HTMLNames.h" 36 #include "MediaList.h" 37 #include "MediaQueryExp.h" 38 #include "WebKitCSSKeyframeRule.h" 39 #include "WebKitCSSKeyframesRule.h" 40 #include <wtf/FastMalloc.h> 41 #include <stdlib.h> 42 #include <string.h> 43 44 using namespace WebCore; 45 using namespace HTMLNames; 46 47 #define YYMALLOC fastMalloc 48 #define YYFREE fastFree 49 50 #define YYENABLE_NLS 0 51 #define YYLTYPE_IS_TRIVIAL 1 52 #define YYMAXDEPTH 10000 53 #define YYDEBUG 0 54 55 // FIXME: Replace with %parse-param { CSSParser* parser } once we can depend on bison 2.x 56 #define YYPARSE_PARAM parser 57 #define YYLEX_PARAM parser 58 59 %} 60 61 %pure_parser 62 63 %union { 64 bool boolean; 65 char character; 66 int integer; 67 double number; 68 CSSParserString string; 69 70 CSSRule* rule; 71 CSSRuleList* ruleList; 72 CSSParserSelector* selector; 73 Vector<OwnPtr<CSSParserSelector> >* selectorList; 74 CSSSelector::MarginBoxType marginBox; 75 CSSSelector::Relation relation; 76 MediaList* mediaList; 77 MediaQuery* mediaQuery; 78 MediaQuery::Restrictor mediaQueryRestrictor; 79 MediaQueryExp* mediaQueryExp; 80 CSSParserValue value; 81 CSSParserValueList* valueList; 82 Vector<OwnPtr<MediaQueryExp> >* mediaQueryExpList; 83 WebKitCSSKeyframeRule* keyframeRule; 84 WebKitCSSKeyframesRule* keyframesRule; 85 float val; 86 } 87 88 %{ 89 90 static inline int cssyyerror(const char*) 91 { 92 return 1; 93 } 94 95 static int cssyylex(YYSTYPE* yylval, void* parser) 96 { 97 return static_cast<CSSParser*>(parser)->lex(yylval); 98 } 99 100 %} 101 102 %expect 54 103 104 %nonassoc LOWEST_PREC 105 106 %left UNIMPORTANT_TOK 107 108 %token WHITESPACE SGML_CD 109 %token TOKEN_EOF 0 110 111 %token INCLUDES 112 %token DASHMATCH 113 %token BEGINSWITH 114 %token ENDSWITH 115 %token CONTAINS 116 117 %token <string> STRING 118 %right <string> IDENT 119 %token <string> NTH 120 121 %nonassoc <string> HEX 122 %nonassoc <string> IDSEL 123 %nonassoc ':' 124 %nonassoc '.' 125 %nonassoc '[' 126 %nonassoc <string> '*' 127 %nonassoc error 128 %left '|' 129 130 %token IMPORT_SYM 131 %token PAGE_SYM 132 %token MEDIA_SYM 133 %token FONT_FACE_SYM 134 %token CHARSET_SYM 135 %token NAMESPACE_SYM 136 %token WEBKIT_RULE_SYM 137 %token WEBKIT_DECLS_SYM 138 %token WEBKIT_KEYFRAME_RULE_SYM 139 %token WEBKIT_KEYFRAMES_SYM 140 %token WEBKIT_VALUE_SYM 141 %token WEBKIT_MEDIAQUERY_SYM 142 %token WEBKIT_SELECTOR_SYM 143 %token <marginBox> TOPLEFTCORNER_SYM 144 %token <marginBox> TOPLEFT_SYM 145 %token <marginBox> TOPCENTER_SYM 146 %token <marginBox> TOPRIGHT_SYM 147 %token <marginBox> TOPRIGHTCORNER_SYM 148 %token <marginBox> BOTTOMLEFTCORNER_SYM 149 %token <marginBox> BOTTOMLEFT_SYM 150 %token <marginBox> BOTTOMCENTER_SYM 151 %token <marginBox> BOTTOMRIGHT_SYM 152 %token <marginBox> BOTTOMRIGHTCORNER_SYM 153 %token <marginBox> LEFTTOP_SYM 154 %token <marginBox> LEFTMIDDLE_SYM 155 %token <marginBox> LEFTBOTTOM_SYM 156 %token <marginBox> RIGHTTOP_SYM 157 %token <marginBox> RIGHTMIDDLE_SYM 158 %token <marginBox> RIGHTBOTTOM_SYM 159 160 %token ATKEYWORD 161 162 %token IMPORTANT_SYM 163 %token MEDIA_ONLY 164 %token MEDIA_NOT 165 %token MEDIA_AND 166 167 %token <number> REMS 168 %token <number> QEMS 169 %token <number> EMS 170 %token <number> EXS 171 %token <number> PXS 172 %token <number> CMS 173 %token <number> MMS 174 %token <number> INS 175 %token <number> PTS 176 %token <number> PCS 177 %token <number> DEGS 178 %token <number> RADS 179 %token <number> GRADS 180 %token <number> TURNS 181 %token <number> MSECS 182 %token <number> SECS 183 %token <number> HERTZ 184 %token <number> KHERTZ 185 %token <string> DIMEN 186 %token <string> INVALIDDIMEN 187 %token <number> PERCENTAGE 188 %token <number> FLOATTOKEN 189 %token <number> INTEGER 190 191 %token <string> URI 192 %token <string> FUNCTION 193 %token <string> ANYFUNCTION 194 %token <string> NOTFUNCTION 195 %token <string> CALCFUNCTION 196 %token <string> MINFUNCTION 197 %token <string> MAXFUNCTION 198 199 %token <string> UNICODERANGE 200 201 %type <relation> combinator 202 203 %type <rule> charset 204 %type <rule> ignored_charset 205 %type <rule> ruleset 206 %type <rule> media 207 %type <rule> import 208 %type <rule> namespace 209 %type <rule> page 210 %type <rule> margin_box 211 %type <rule> font_face 212 %type <rule> keyframes 213 %type <rule> invalid_rule 214 %type <rule> save_block 215 %type <rule> invalid_at 216 %type <rule> rule 217 %type <rule> valid_rule 218 %type <ruleList> block_rule_list 219 %type <rule> block_rule 220 %type <rule> block_valid_rule 221 222 %type <string> maybe_ns_prefix 223 224 %type <string> namespace_selector 225 226 %type <string> string_or_uri 227 %type <string> ident_or_string 228 %type <string> medium 229 %type <marginBox> margin_sym 230 231 %type <string> media_feature 232 %type <mediaList> media_list 233 %type <mediaList> maybe_media_list 234 %type <mediaQuery> media_query 235 %type <mediaQueryRestrictor> maybe_media_restrictor 236 %type <valueList> maybe_media_value 237 %type <mediaQueryExp> media_query_exp 238 %type <mediaQueryExpList> media_query_exp_list 239 %type <mediaQueryExpList> maybe_and_media_query_exp_list 240 241 %type <string> keyframe_name 242 %type <keyframeRule> keyframe_rule 243 %type <keyframesRule> keyframes_rule 244 %type <valueList> key_list 245 %type <value> key 246 247 %type <integer> property 248 249 %type <selector> specifier 250 %type <selector> specifier_list 251 %type <selector> simple_selector 252 %type <selector> selector 253 %type <selectorList> selector_list 254 %type <selectorList> simple_selector_list 255 %type <selector> selector_with_trailing_whitespace 256 %type <selector> class 257 %type <selector> attrib 258 %type <selector> pseudo 259 %type <selector> pseudo_page 260 %type <selector> page_selector 261 262 %type <boolean> declaration_list 263 %type <boolean> decl_list 264 %type <boolean> declaration 265 %type <boolean> declarations_and_margins 266 267 %type <boolean> prio 268 269 %type <integer> match 270 %type <integer> unary_operator 271 %type <integer> maybe_unary_operator 272 %type <character> operator 273 274 %type <valueList> expr 275 %type <value> term 276 %type <value> unary_term 277 %type <value> function 278 %type <value> calc_func_term 279 %type <character> calc_func_operator 280 %type <valueList> calc_func_expr 281 %type <valueList> calc_func_expr_list 282 %type <valueList> calc_func_paren_expr 283 %type <value> calc_function 284 %type <string> min_or_max 285 %type <value> min_or_max_function 286 287 %type <string> element_name 288 %type <string> attr_name 289 290 %% 291 292 stylesheet: 293 maybe_space maybe_charset maybe_sgml rule_list 294 | webkit_rule maybe_space 295 | webkit_decls maybe_space 296 | webkit_value maybe_space 297 | webkit_mediaquery maybe_space 298 | webkit_selector maybe_space 299 | webkit_keyframe_rule maybe_space 300 ; 301 302 webkit_rule: 303 WEBKIT_RULE_SYM '{' maybe_space valid_rule maybe_space '}' { 304 static_cast<CSSParser*>(parser)->m_rule = $4; 305 } 306 ; 307 308 webkit_keyframe_rule: 309 WEBKIT_KEYFRAME_RULE_SYM '{' maybe_space keyframe_rule maybe_space '}' { 310 static_cast<CSSParser*>(parser)->m_keyframe = $4; 311 } 312 ; 313 314 webkit_decls: 315 WEBKIT_DECLS_SYM '{' maybe_space_before_declaration declaration_list '}' { 316 /* can be empty */ 317 } 318 ; 319 320 webkit_value: 321 WEBKIT_VALUE_SYM '{' maybe_space expr '}' { 322 CSSParser* p = static_cast<CSSParser*>(parser); 323 if ($4) { 324 p->m_valueList = p->sinkFloatingValueList($4); 325 int oldParsedProperties = p->m_numParsedProperties; 326 if (!p->parseValue(p->m_id, p->m_important)) 327 p->rollbackLastProperties(p->m_numParsedProperties - oldParsedProperties); 328 delete p->m_valueList; 329 p->m_valueList = 0; 330 } 331 } 332 ; 333 334 webkit_mediaquery: 335 WEBKIT_MEDIAQUERY_SYM WHITESPACE maybe_space media_query '}' { 336 CSSParser* p = static_cast<CSSParser*>(parser); 337 p->m_mediaQuery = p->sinkFloatingMediaQuery($4); 338 } 339 ; 340 341 webkit_selector: 342 WEBKIT_SELECTOR_SYM '{' maybe_space selector_list '}' { 343 if ($4) { 344 CSSParser* p = static_cast<CSSParser*>(parser); 345 if (p->m_selectorListForParseSelector) 346 p->m_selectorListForParseSelector->adoptSelectorVector(*$4); 347 } 348 } 349 ; 350 351 maybe_space: 352 /* empty */ %prec UNIMPORTANT_TOK 353 | maybe_space WHITESPACE 354 ; 355 356 maybe_sgml: 357 /* empty */ 358 | maybe_sgml SGML_CD 359 | maybe_sgml WHITESPACE 360 ; 361 362 maybe_charset: 363 /* empty */ 364 | charset { 365 } 366 ; 367 368 closing_brace: 369 '}' 370 | %prec LOWEST_PREC TOKEN_EOF 371 ; 372 373 charset: 374 CHARSET_SYM maybe_space STRING maybe_space ';' { 375 CSSParser* p = static_cast<CSSParser*>(parser); 376 $$ = static_cast<CSSParser*>(parser)->createCharsetRule($3); 377 if ($$ && p->m_styleSheet) 378 p->m_styleSheet->append($$); 379 } 380 | CHARSET_SYM error invalid_block { 381 } 382 | CHARSET_SYM error ';' { 383 } 384 ; 385 386 ignored_charset: 387 CHARSET_SYM maybe_space STRING maybe_space ';' { 388 // Ignore any @charset rule not at the beginning of the style sheet. 389 $$ = 0; 390 } 391 ; 392 393 rule_list: 394 /* empty */ 395 | rule_list rule maybe_sgml { 396 CSSParser* p = static_cast<CSSParser*>(parser); 397 if ($2 && p->m_styleSheet) 398 p->m_styleSheet->append($2); 399 } 400 ; 401 402 valid_rule: 403 before_ruleset ruleset { 404 $$ = $2; 405 } 406 | media 407 | page 408 | font_face 409 | keyframes 410 | namespace 411 | import 412 ; 413 414 rule: 415 valid_rule { 416 static_cast<CSSParser*>(parser)->m_hadSyntacticallyValidCSSRule = true; 417 } 418 | ignored_charset 419 | invalid_rule 420 | invalid_at 421 ; 422 423 block_rule_list: 424 /* empty */ { $$ = 0; } 425 | block_rule_list block_rule maybe_sgml { 426 $$ = $1; 427 if ($2) { 428 if (!$$) 429 $$ = static_cast<CSSParser*>(parser)->createRuleList(); 430 $$->append($2); 431 } 432 } 433 ; 434 435 block_valid_rule: 436 ruleset 437 | page 438 | font_face 439 | keyframes 440 ; 441 442 block_rule: 443 block_valid_rule 444 | invalid_rule 445 | invalid_at 446 | namespace 447 | import 448 | media 449 ; 450 451 452 import: 453 IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list ';' { 454 $$ = static_cast<CSSParser*>(parser)->createImportRule($3, $5); 455 } 456 | IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list invalid_block { 457 $$ = 0; 458 } 459 | IMPORT_SYM error ';' { 460 $$ = 0; 461 } 462 | IMPORT_SYM error invalid_block { 463 $$ = 0; 464 } 465 ; 466 467 namespace: 468 NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space ';' { 469 static_cast<CSSParser*>(parser)->addNamespace($3, $4); 470 $$ = 0; 471 } 472 | NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space invalid_block { 473 $$ = 0; 474 } 475 | NAMESPACE_SYM error invalid_block { 476 $$ = 0; 477 } 478 | NAMESPACE_SYM error ';' { 479 $$ = 0; 480 } 481 ; 482 483 maybe_ns_prefix: 484 /* empty */ { $$.characters = 0; } 485 | IDENT maybe_space { $$ = $1; } 486 ; 487 488 string_or_uri: 489 STRING 490 | URI 491 ; 492 493 media_feature: 494 IDENT maybe_space { 495 $$ = $1; 496 } 497 ; 498 499 maybe_media_value: 500 /*empty*/ { 501 $$ = 0; 502 } 503 | ':' maybe_space expr maybe_space { 504 $$ = $3; 505 } 506 ; 507 508 media_query_exp: 509 '(' maybe_space media_feature maybe_space maybe_media_value ')' maybe_space { 510 $3.lower(); 511 $$ = static_cast<CSSParser*>(parser)->createFloatingMediaQueryExp($3, $5); 512 } 513 ; 514 515 media_query_exp_list: 516 media_query_exp { 517 CSSParser* p = static_cast<CSSParser*>(parser); 518 $$ = p->createFloatingMediaQueryExpList(); 519 $$->append(p->sinkFloatingMediaQueryExp($1)); 520 } 521 | media_query_exp_list maybe_space MEDIA_AND maybe_space media_query_exp { 522 $$ = $1; 523 $$->append(static_cast<CSSParser*>(parser)->sinkFloatingMediaQueryExp($5)); 524 } 525 ; 526 527 maybe_and_media_query_exp_list: 528 /*empty*/ { 529 $$ = static_cast<CSSParser*>(parser)->createFloatingMediaQueryExpList(); 530 } 531 | MEDIA_AND maybe_space media_query_exp_list { 532 $$ = $3; 533 } 534 ; 535 536 maybe_media_restrictor: 537 /*empty*/ { 538 $$ = MediaQuery::None; 539 } 540 | MEDIA_ONLY { 541 $$ = MediaQuery::Only; 542 } 543 | MEDIA_NOT { 544 $$ = MediaQuery::Not; 545 } 546 ; 547 548 media_query: 549 media_query_exp_list { 550 CSSParser* p = static_cast<CSSParser*>(parser); 551 $$ = p->createFloatingMediaQuery(p->sinkFloatingMediaQueryExpList($1)); 552 } 553 | 554 maybe_media_restrictor maybe_space medium maybe_and_media_query_exp_list { 555 CSSParser* p = static_cast<CSSParser*>(parser); 556 $3.lower(); 557 $$ = p->createFloatingMediaQuery($1, $3, p->sinkFloatingMediaQueryExpList($4)); 558 } 559 ; 560 561 maybe_media_list: 562 /* empty */ { 563 $$ = static_cast<CSSParser*>(parser)->createMediaList(); 564 } 565 | media_list 566 ; 567 568 media_list: 569 media_query { 570 CSSParser* p = static_cast<CSSParser*>(parser); 571 $$ = p->createMediaList(); 572 $$->appendMediaQuery(p->sinkFloatingMediaQuery($1)); 573 } 574 | media_list ',' maybe_space media_query { 575 $$ = $1; 576 if ($$) 577 $$->appendMediaQuery(static_cast<CSSParser*>(parser)->sinkFloatingMediaQuery($4)); 578 } 579 | media_list error { 580 $$ = 0; 581 } 582 ; 583 584 media: 585 MEDIA_SYM maybe_space media_list '{' maybe_space block_rule_list save_block { 586 $$ = static_cast<CSSParser*>(parser)->createMediaRule($3, $6); 587 } 588 | MEDIA_SYM maybe_space '{' maybe_space block_rule_list save_block { 589 $$ = static_cast<CSSParser*>(parser)->createMediaRule(0, $5); 590 } 591 ; 592 593 medium: 594 IDENT maybe_space { 595 $$ = $1; 596 } 597 ; 598 599 keyframes: 600 WEBKIT_KEYFRAMES_SYM maybe_space keyframe_name maybe_space '{' maybe_space keyframes_rule '}' { 601 $$ = $7; 602 $7->setNameInternal($3); 603 } 604 ; 605 606 keyframe_name: 607 IDENT 608 | STRING 609 ; 610 611 keyframes_rule: 612 /* empty */ { $$ = static_cast<CSSParser*>(parser)->createKeyframesRule(); } 613 | keyframes_rule keyframe_rule maybe_space { 614 $$ = $1; 615 if ($2) 616 $$->append($2); 617 } 618 ; 619 620 keyframe_rule: 621 key_list maybe_space '{' maybe_space declaration_list '}' { 622 $$ = static_cast<CSSParser*>(parser)->createKeyframeRule($1); 623 } 624 ; 625 626 key_list: 627 key { 628 CSSParser* p = static_cast<CSSParser*>(parser); 629 $$ = p->createFloatingValueList(); 630 $$->addValue(p->sinkFloatingValue($1)); 631 } 632 | key_list maybe_space ',' maybe_space key { 633 CSSParser* p = static_cast<CSSParser*>(parser); 634 $$ = $1; 635 if ($$) 636 $$->addValue(p->sinkFloatingValue($5)); 637 } 638 ; 639 640 key: 641 PERCENTAGE { $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } 642 | IDENT { 643 $$.id = 0; $$.isInt = false; $$.unit = CSSPrimitiveValue::CSS_NUMBER; 644 CSSParserString& str = $1; 645 if (equalIgnoringCase("from", str.characters, str.length)) 646 $$.fValue = 0; 647 else if (equalIgnoringCase("to", str.characters, str.length)) 648 $$.fValue = 100; 649 else 650 YYERROR; 651 } 652 ; 653 654 page: 655 PAGE_SYM maybe_space page_selector maybe_space 656 '{' maybe_space declarations_and_margins closing_brace { 657 CSSParser* p = static_cast<CSSParser*>(parser); 658 if ($3) 659 $$ = p->createPageRule(p->sinkFloatingSelector($3)); 660 else { 661 // Clear properties in the invalid @page rule. 662 p->clearProperties(); 663 // Also clear margin at-rules here once we fully implement margin at-rules parsing. 664 $$ = 0; 665 } 666 } 667 | PAGE_SYM error invalid_block { 668 $$ = 0; 669 } 670 | PAGE_SYM error ';' { 671 $$ = 0; 672 } 673 ; 674 675 page_selector: 676 IDENT { 677 CSSParser* p = static_cast<CSSParser*>(parser); 678 $$ = p->createFloatingSelector(); 679 $$->setTag(QualifiedName(nullAtom, $1, p->m_defaultNamespace)); 680 $$->setForPage(); 681 } 682 | IDENT pseudo_page { 683 CSSParser* p = static_cast<CSSParser*>(parser); 684 $$ = $2; 685 if ($$) { 686 $$->setTag(QualifiedName(nullAtom, $1, p->m_defaultNamespace)); 687 $$->setForPage(); 688 } 689 } 690 | pseudo_page { 691 $$ = $1; 692 if ($$) 693 $$->setForPage(); 694 } 695 | /* empty */ { 696 CSSParser* p = static_cast<CSSParser*>(parser); 697 $$ = p->createFloatingSelector(); 698 $$->setForPage(); 699 } 700 ; 701 702 declarations_and_margins: 703 declaration_list 704 | declarations_and_margins margin_box maybe_space declaration_list 705 ; 706 707 margin_box: 708 margin_sym { 709 static_cast<CSSParser*>(parser)->startDeclarationsForMarginBox(); 710 } maybe_space '{' maybe_space declaration_list closing_brace { 711 $$ = static_cast<CSSParser*>(parser)->createMarginAtRule($1); 712 } 713 ; 714 715 margin_sym : 716 TOPLEFTCORNER_SYM { 717 $$ = CSSSelector::TopLeftCornerMarginBox; 718 } 719 | TOPLEFT_SYM { 720 $$ = CSSSelector::TopLeftMarginBox; 721 } 722 | TOPCENTER_SYM { 723 $$ = CSSSelector::TopCenterMarginBox; 724 } 725 | TOPRIGHT_SYM { 726 $$ = CSSSelector::TopRightMarginBox; 727 } 728 | TOPRIGHTCORNER_SYM { 729 $$ = CSSSelector::TopRightCornerMarginBox; 730 } 731 | BOTTOMLEFTCORNER_SYM { 732 $$ = CSSSelector::BottomLeftCornerMarginBox; 733 } 734 | BOTTOMLEFT_SYM { 735 $$ = CSSSelector::BottomLeftMarginBox; 736 } 737 | BOTTOMCENTER_SYM { 738 $$ = CSSSelector::BottomCenterMarginBox; 739 } 740 | BOTTOMRIGHT_SYM { 741 $$ = CSSSelector::BottomRightMarginBox; 742 } 743 | BOTTOMRIGHTCORNER_SYM { 744 $$ = CSSSelector::BottomRightCornerMarginBox; 745 } 746 | LEFTTOP_SYM { 747 $$ = CSSSelector::LeftTopMarginBox; 748 } 749 | LEFTMIDDLE_SYM { 750 $$ = CSSSelector::LeftMiddleMarginBox; 751 } 752 | LEFTBOTTOM_SYM { 753 $$ = CSSSelector::LeftBottomMarginBox; 754 } 755 | RIGHTTOP_SYM { 756 $$ = CSSSelector::RightTopMarginBox; 757 } 758 | RIGHTMIDDLE_SYM { 759 $$ = CSSSelector::RightMiddleMarginBox; 760 } 761 | RIGHTBOTTOM_SYM { 762 $$ = CSSSelector::RightBottomMarginBox; 763 } 764 ; 765 766 font_face: 767 FONT_FACE_SYM maybe_space 768 '{' maybe_space declaration_list '}' maybe_space { 769 $$ = static_cast<CSSParser*>(parser)->createFontFaceRule(); 770 } 771 | FONT_FACE_SYM error invalid_block { 772 $$ = 0; 773 } 774 | FONT_FACE_SYM error ';' { 775 $$ = 0; 776 } 777 ; 778 779 combinator: 780 '+' maybe_space { $$ = CSSSelector::DirectAdjacent; } 781 | '~' maybe_space { $$ = CSSSelector::IndirectAdjacent; } 782 | '>' maybe_space { $$ = CSSSelector::Child; } 783 ; 784 785 maybe_unary_operator: 786 unary_operator { $$ = $1; } 787 | { $$ = 1; } 788 ; 789 790 unary_operator: 791 '-' { $$ = -1; } 792 | '+' { $$ = 1; } 793 ; 794 795 maybe_space_before_declaration: 796 maybe_space { 797 CSSParser* p = static_cast<CSSParser*>(parser); 798 p->markPropertyStart(); 799 } 800 ; 801 802 before_ruleset: 803 /* empty */ { 804 CSSParser* p = static_cast<CSSParser*>(parser); 805 p->markSelectorListStart(); 806 } 807 ; 808 809 before_rule_opening_brace: 810 /* empty */ { 811 CSSParser* p = static_cast<CSSParser*>(parser); 812 p->markSelectorListEnd(); 813 } 814 ; 815 816 ruleset: 817 selector_list before_rule_opening_brace '{' maybe_space_before_declaration declaration_list closing_brace { 818 CSSParser* p = static_cast<CSSParser*>(parser); 819 $$ = p->createStyleRule($1); 820 } 821 ; 822 823 selector_list: 824 selector %prec UNIMPORTANT_TOK { 825 if ($1) { 826 CSSParser* p = static_cast<CSSParser*>(parser); 827 $$ = p->reusableSelectorVector(); 828 $$->shrink(0); 829 $$->append(p->sinkFloatingSelector($1)); 830 p->updateLastSelectorLineAndPosition(); 831 } 832 } 833 | selector_list ',' maybe_space selector %prec UNIMPORTANT_TOK { 834 if ($1 && $4) { 835 CSSParser* p = static_cast<CSSParser*>(parser); 836 $$ = $1; 837 $$->append(p->sinkFloatingSelector($4)); 838 p->updateLastSelectorLineAndPosition(); 839 } else 840 $$ = 0; 841 } 842 | selector_list error { 843 $$ = 0; 844 } 845 ; 846 847 selector_with_trailing_whitespace: 848 selector WHITESPACE { 849 $$ = $1; 850 } 851 ; 852 853 selector: 854 simple_selector { 855 $$ = $1; 856 } 857 | selector_with_trailing_whitespace 858 { 859 $$ = $1; 860 } 861 | selector_with_trailing_whitespace simple_selector 862 { 863 $$ = $2; 864 if (!$1) 865 $$ = 0; 866 else if ($$) { 867 CSSParser* p = static_cast<CSSParser*>(parser); 868 CSSParserSelector* end = $$; 869 while (end->tagHistory()) 870 end = end->tagHistory(); 871 end->setRelation(CSSSelector::Descendant); 872 end->setTagHistory(p->sinkFloatingSelector($1)); 873 } 874 } 875 | selector combinator simple_selector { 876 $$ = $3; 877 if (!$1) 878 $$ = 0; 879 else if ($$) { 880 CSSParser* p = static_cast<CSSParser*>(parser); 881 CSSParserSelector* end = $$; 882 while (end->tagHistory()) 883 end = end->tagHistory(); 884 end->setRelation($2); 885 end->setTagHistory(p->sinkFloatingSelector($1)); 886 } 887 } 888 | selector error { 889 $$ = 0; 890 } 891 ; 892 893 namespace_selector: 894 /* empty */ '|' { $$.characters = 0; $$.length = 0; } 895 | '*' '|' { static UChar star = '*'; $$.characters = ☆ $$.length = 1; } 896 | IDENT '|' { $$ = $1; } 897 ; 898 899 simple_selector: 900 element_name { 901 CSSParser* p = static_cast<CSSParser*>(parser); 902 $$ = p->createFloatingSelector(); 903 $$->setTag(QualifiedName(nullAtom, $1, p->m_defaultNamespace)); 904 } 905 | element_name specifier_list { 906 $$ = $2; 907 if ($$) 908 static_cast<CSSParser*>(parser)->updateSpecifiersWithElementName(nullAtom, $1, $$); 909 } 910 | specifier_list { 911 $$ = $1; 912 if ($$) 913 static_cast<CSSParser*>(parser)->updateSpecifiersWithElementName(nullAtom, starAtom, $$); 914 } 915 | namespace_selector element_name { 916 AtomicString namespacePrefix = $1; 917 CSSParser* p = static_cast<CSSParser*>(parser); 918 $$ = p->createFloatingSelector(); 919 if (p->m_styleSheet) 920 $$->setTag(QualifiedName(namespacePrefix, $2, 921 p->m_styleSheet->determineNamespace(namespacePrefix))); 922 else // FIXME: Shouldn't this case be an error? 923 $$->setTag(QualifiedName(nullAtom, $2, p->m_defaultNamespace)); 924 } 925 | namespace_selector element_name specifier_list { 926 $$ = $3; 927 if ($$) 928 static_cast<CSSParser*>(parser)->updateSpecifiersWithElementName($1, $2, $$); 929 } 930 | namespace_selector specifier_list { 931 $$ = $2; 932 if ($$) 933 static_cast<CSSParser*>(parser)->updateSpecifiersWithElementName($1, starAtom, $$); 934 } 935 ; 936 937 simple_selector_list: 938 simple_selector %prec UNIMPORTANT_TOK { 939 if ($1) { 940 CSSParser* p = static_cast<CSSParser*>(parser); 941 $$ = p->createFloatingSelectorVector(); 942 $$->append(p->sinkFloatingSelector($1)); 943 } else 944 $$ = 0 945 } 946 | simple_selector_list maybe_space ',' maybe_space simple_selector %prec UNIMPORTANT_TOK { 947 if ($1 && $5) { 948 CSSParser* p = static_cast<CSSParser*>(parser); 949 $$ = $1; 950 $$->append(p->sinkFloatingSelector($5)); 951 } else 952 $$ = 0; 953 } 954 | simple_selector_list error { 955 $$ = 0; 956 } 957 ; 958 959 element_name: 960 IDENT { 961 CSSParserString& str = $1; 962 CSSParser* p = static_cast<CSSParser*>(parser); 963 Document* doc = p->document(); 964 if (doc && doc->isHTMLDocument()) 965 str.lower(); 966 $$ = str; 967 } 968 | '*' { 969 static UChar star = '*'; 970 $$.characters = ☆ 971 $$.length = 1; 972 } 973 ; 974 975 specifier_list: 976 specifier { 977 $$ = $1; 978 } 979 | specifier_list specifier { 980 if (!$2) 981 $$ = 0; 982 else if ($1) { 983 CSSParser* p = static_cast<CSSParser*>(parser); 984 CSSParserSelector* end; 985 CSSParserSelector* history; 986 // Ensure that unknown pseudo element always stays at the top of selector chain. 987 if ($2->isUnknownPseudoElement()) { 988 end = $2; 989 history = $1; 990 } else { 991 end = $1; 992 history = $2; 993 } 994 $$ = end; 995 while(end->tagHistory()) 996 end = end->tagHistory(); 997 end->setRelation(CSSSelector::SubSelector); 998 end->setTagHistory(p->sinkFloatingSelector(history)); 999 } 1000 } 1001 | specifier_list error { 1002 $$ = 0; 1003 } 1004 ; 1005 1006 specifier: 1007 IDSEL { 1008 CSSParser* p = static_cast<CSSParser*>(parser); 1009 $$ = p->createFloatingSelector(); 1010 $$->setMatch(CSSSelector::Id); 1011 if (!p->m_strict) 1012 $1.lower(); 1013 $$->setValue($1); 1014 } 1015 | HEX { 1016 if ($1.characters[0] >= '0' && $1.characters[0] <= '9') { 1017 $$ = 0; 1018 } else { 1019 CSSParser* p = static_cast<CSSParser*>(parser); 1020 $$ = p->createFloatingSelector(); 1021 $$->setMatch(CSSSelector::Id); 1022 if (!p->m_strict) 1023 $1.lower(); 1024 $$->setValue($1); 1025 } 1026 } 1027 | class 1028 | attrib 1029 | pseudo 1030 ; 1031 1032 class: 1033 '.' IDENT { 1034 CSSParser* p = static_cast<CSSParser*>(parser); 1035 $$ = p->createFloatingSelector(); 1036 $$->setMatch(CSSSelector::Class); 1037 if (!p->m_strict) 1038 $2.lower(); 1039 $$->setValue($2); 1040 } 1041 ; 1042 1043 attr_name: 1044 IDENT maybe_space { 1045 CSSParserString& str = $1; 1046 CSSParser* p = static_cast<CSSParser*>(parser); 1047 Document* doc = p->document(); 1048 if (doc && doc->isHTMLDocument()) 1049 str.lower(); 1050 $$ = str; 1051 } 1052 ; 1053 1054 attrib: 1055 '[' maybe_space attr_name ']' { 1056 $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); 1057 $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom)); 1058 $$->setMatch(CSSSelector::Set); 1059 } 1060 | '[' maybe_space attr_name match maybe_space ident_or_string maybe_space ']' { 1061 $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); 1062 $$->setAttribute(QualifiedName(nullAtom, $3, nullAtom)); 1063 $$->setMatch((CSSSelector::Match)$4); 1064 $$->setValue($6); 1065 } 1066 | '[' maybe_space namespace_selector attr_name ']' { 1067 AtomicString namespacePrefix = $3; 1068 CSSParser* p = static_cast<CSSParser*>(parser); 1069 $$ = p->createFloatingSelector(); 1070 $$->setAttribute(QualifiedName(namespacePrefix, $4, 1071 p->m_styleSheet->determineNamespace(namespacePrefix))); 1072 $$->setMatch(CSSSelector::Set); 1073 } 1074 | '[' maybe_space namespace_selector attr_name match maybe_space ident_or_string maybe_space ']' { 1075 AtomicString namespacePrefix = $3; 1076 CSSParser* p = static_cast<CSSParser*>(parser); 1077 $$ = p->createFloatingSelector(); 1078 $$->setAttribute(QualifiedName(namespacePrefix, $4, 1079 p->m_styleSheet->determineNamespace(namespacePrefix))); 1080 $$->setMatch((CSSSelector::Match)$5); 1081 $$->setValue($7); 1082 } 1083 ; 1084 1085 match: 1086 '=' { 1087 $$ = CSSSelector::Exact; 1088 } 1089 | INCLUDES { 1090 $$ = CSSSelector::List; 1091 } 1092 | DASHMATCH { 1093 $$ = CSSSelector::Hyphen; 1094 } 1095 | BEGINSWITH { 1096 $$ = CSSSelector::Begin; 1097 } 1098 | ENDSWITH { 1099 $$ = CSSSelector::End; 1100 } 1101 | CONTAINS { 1102 $$ = CSSSelector::Contain; 1103 } 1104 ; 1105 1106 ident_or_string: 1107 IDENT 1108 | STRING 1109 ; 1110 1111 pseudo_page: 1112 ':' IDENT { 1113 $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); 1114 $$->setMatch(CSSSelector::PagePseudoClass); 1115 $2.lower(); 1116 $$->setValue($2); 1117 CSSSelector::PseudoType type = $$->pseudoType(); 1118 if (type == CSSSelector::PseudoUnknown) 1119 $$ = 0; 1120 } 1121 1122 pseudo: 1123 ':' IDENT { 1124 $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); 1125 $$->setMatch(CSSSelector::PseudoClass); 1126 $2.lower(); 1127 $$->setValue($2); 1128 CSSSelector::PseudoType type = $$->pseudoType(); 1129 if (type == CSSSelector::PseudoUnknown) 1130 $$ = 0; 1131 } 1132 | ':' ':' IDENT { 1133 $$ = static_cast<CSSParser*>(parser)->createFloatingSelector(); 1134 $$->setMatch(CSSSelector::PseudoElement); 1135 $3.lower(); 1136 $$->setValue($3); 1137 // FIXME: This call is needed to force selector to compute the pseudoType early enough. 1138 $$->pseudoType(); 1139 } 1140 // use by :-webkit-any. 1141 // FIXME: should we support generic selectors here or just simple_selectors? 1142 // Use simple_selector_list for now to match -moz-any. 1143 // See http://lists.w3.org/Archives/Public/www-style/2010Sep/0566.html for some 1144 // related discussion with respect to :not. 1145 | ':' ANYFUNCTION maybe_space simple_selector_list maybe_space ')' { 1146 if ($4) { 1147 CSSParser *p = static_cast<CSSParser*>(parser); 1148 $$ = p->createFloatingSelector(); 1149 $$->setMatch(CSSSelector::PseudoClass); 1150 $$->adoptSelectorVector(*p->sinkFloatingSelectorVector($4)); 1151 $2.lower(); 1152 $$->setValue($2); 1153 CSSSelector::PseudoType type = $$->pseudoType(); 1154 if (type != CSSSelector::PseudoAny) 1155 $$ = 0; 1156 } else 1157 $$ = 0; 1158 } 1159 // used by :nth-*(ax+b) 1160 | ':' FUNCTION maybe_space NTH maybe_space ')' { 1161 CSSParser *p = static_cast<CSSParser*>(parser); 1162 $$ = p->createFloatingSelector(); 1163 $$->setMatch(CSSSelector::PseudoClass); 1164 $$->setArgument($4); 1165 $$->setValue($2); 1166 CSSSelector::PseudoType type = $$->pseudoType(); 1167 if (type == CSSSelector::PseudoUnknown) 1168 $$ = 0; 1169 } 1170 // used by :nth-* 1171 | ':' FUNCTION maybe_space maybe_unary_operator INTEGER maybe_space ')' { 1172 CSSParser *p = static_cast<CSSParser*>(parser); 1173 $$ = p->createFloatingSelector(); 1174 $$->setMatch(CSSSelector::PseudoClass); 1175 $$->setArgument(String::number($4 * $5)); 1176 $$->setValue($2); 1177 CSSSelector::PseudoType type = $$->pseudoType(); 1178 if (type == CSSSelector::PseudoUnknown) 1179 $$ = 0; 1180 } 1181 // used by :nth-*(odd/even) and :lang 1182 | ':' FUNCTION maybe_space IDENT maybe_space ')' { 1183 CSSParser *p = static_cast<CSSParser*>(parser); 1184 $$ = p->createFloatingSelector(); 1185 $$->setMatch(CSSSelector::PseudoClass); 1186 $$->setArgument($4); 1187 $2.lower(); 1188 $$->setValue($2); 1189 CSSSelector::PseudoType type = $$->pseudoType(); 1190 if (type == CSSSelector::PseudoUnknown) 1191 $$ = 0; 1192 else if (type == CSSSelector::PseudoNthChild || 1193 type == CSSSelector::PseudoNthOfType || 1194 type == CSSSelector::PseudoNthLastChild || 1195 type == CSSSelector::PseudoNthLastOfType) { 1196 if (!isValidNthToken($4)) 1197 $$ = 0; 1198 } 1199 } 1200 // used by :not 1201 | ':' NOTFUNCTION maybe_space simple_selector maybe_space ')' { 1202 if (!$4 || !$4->isSimple()) 1203 $$ = 0; 1204 else { 1205 CSSParser* p = static_cast<CSSParser*>(parser); 1206 $$ = p->createFloatingSelector(); 1207 $$->setMatch(CSSSelector::PseudoClass); 1208 1209 Vector<OwnPtr<CSSParserSelector> > selectorVector; 1210 selectorVector.append(p->sinkFloatingSelector($4)); 1211 $$->adoptSelectorVector(selectorVector); 1212 1213 $2.lower(); 1214 $$->setValue($2); 1215 } 1216 } 1217 ; 1218 1219 declaration_list: 1220 declaration { 1221 $$ = $1; 1222 } 1223 | decl_list declaration { 1224 $$ = $1; 1225 if ( $2 ) 1226 $$ = $2; 1227 } 1228 | decl_list { 1229 $$ = $1; 1230 } 1231 | error invalid_block_list error { 1232 $$ = false; 1233 } 1234 | error { 1235 $$ = false; 1236 } 1237 | decl_list error { 1238 $$ = $1; 1239 } 1240 | decl_list invalid_block_list { 1241 $$ = $1; 1242 } 1243 ; 1244 1245 decl_list: 1246 declaration ';' maybe_space { 1247 CSSParser* p = static_cast<CSSParser*>(parser); 1248 p->markPropertyStart(); 1249 $$ = $1; 1250 } 1251 | declaration invalid_block_list maybe_space { 1252 $$ = false; 1253 } 1254 | declaration invalid_block_list ';' maybe_space { 1255 $$ = false; 1256 } 1257 | error ';' maybe_space { 1258 CSSParser* p = static_cast<CSSParser*>(parser); 1259 p->markPropertyStart(); 1260 $$ = false; 1261 } 1262 | error invalid_block_list error ';' maybe_space { 1263 $$ = false; 1264 } 1265 | decl_list declaration ';' maybe_space { 1266 CSSParser* p = static_cast<CSSParser*>(parser); 1267 p->markPropertyStart(); 1268 $$ = $1; 1269 if ($2) 1270 $$ = $2; 1271 } 1272 | decl_list error ';' maybe_space { 1273 CSSParser* p = static_cast<CSSParser*>(parser); 1274 p->markPropertyStart(); 1275 $$ = $1; 1276 } 1277 | decl_list error invalid_block_list error ';' maybe_space { 1278 CSSParser* p = static_cast<CSSParser*>(parser); 1279 p->markPropertyStart(); 1280 $$ = $1; 1281 } 1282 ; 1283 1284 declaration: 1285 property ':' maybe_space expr prio { 1286 $$ = false; 1287 CSSParser* p = static_cast<CSSParser*>(parser); 1288 bool isPropertyParsed = false; 1289 if ($1 && $4) { 1290 p->m_valueList = p->sinkFloatingValueList($4); 1291 int oldParsedProperties = p->m_numParsedProperties; 1292 $$ = p->parseValue($1, $5); 1293 if (!$$) 1294 p->rollbackLastProperties(p->m_numParsedProperties - oldParsedProperties); 1295 else 1296 isPropertyParsed = true; 1297 delete p->m_valueList; 1298 p->m_valueList = 0; 1299 } 1300 p->markPropertyEnd($5, isPropertyParsed); 1301 } 1302 | 1303 property error { 1304 $$ = false; 1305 } 1306 | 1307 property ':' maybe_space error expr prio { 1308 /* The default movable type template has letter-spacing: .none; Handle this by looking for 1309 error tokens at the start of an expr, recover the expr and then treat as an error, cleaning 1310 up and deleting the shifted expr. */ 1311 CSSParser* p = static_cast<CSSParser*>(parser); 1312 p->markPropertyEnd(false, false); 1313 $$ = false; 1314 } 1315 | 1316 property ':' maybe_space expr prio error { 1317 /* When we encounter something like p {color: red !important fail;} we should drop the declaration */ 1318 CSSParser* p = static_cast<CSSParser*>(parser); 1319 p->markPropertyEnd(false, false); 1320 $$ = false; 1321 } 1322 | 1323 IMPORTANT_SYM maybe_space { 1324 /* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */ 1325 $$ = false; 1326 } 1327 | 1328 property ':' maybe_space { 1329 /* div { font-family: } Just reduce away this property with no value. */ 1330 CSSParser* p = static_cast<CSSParser*>(parser); 1331 p->markPropertyEnd(false, false); 1332 $$ = false; 1333 } 1334 | 1335 property ':' maybe_space error { 1336 /* if we come across rules with invalid values like this case: p { weight: *; }, just discard the rule */ 1337 CSSParser* p = static_cast<CSSParser*>(parser); 1338 p->markPropertyEnd(false, false); 1339 $$ = false; 1340 } 1341 | 1342 property invalid_block { 1343 /* if we come across: div { color{;color:maroon} }, ignore everything within curly brackets */ 1344 $$ = false; 1345 } 1346 ; 1347 1348 property: 1349 IDENT maybe_space { 1350 $$ = cssPropertyID($1); 1351 } 1352 ; 1353 1354 prio: 1355 IMPORTANT_SYM maybe_space { $$ = true; } 1356 | /* empty */ { $$ = false; } 1357 ; 1358 1359 expr: 1360 term { 1361 CSSParser* p = static_cast<CSSParser*>(parser); 1362 $$ = p->createFloatingValueList(); 1363 $$->addValue(p->sinkFloatingValue($1)); 1364 } 1365 | expr operator term { 1366 CSSParser* p = static_cast<CSSParser*>(parser); 1367 $$ = $1; 1368 if ($$) { 1369 if ($2) { 1370 CSSParserValue v; 1371 v.id = 0; 1372 v.unit = CSSParserValue::Operator; 1373 v.iValue = $2; 1374 $$->addValue(v); 1375 } 1376 $$->addValue(p->sinkFloatingValue($3)); 1377 } 1378 } 1379 | expr invalid_block_list { 1380 $$ = 0; 1381 } 1382 | expr invalid_block_list error { 1383 $$ = 0; 1384 } 1385 | expr error { 1386 $$ = 0; 1387 } 1388 ; 1389 1390 operator: 1391 '/' maybe_space { 1392 $$ = '/'; 1393 } 1394 | ',' maybe_space { 1395 $$ = ','; 1396 } 1397 | /* empty */ { 1398 $$ = 0; 1399 } 1400 ; 1401 1402 term: 1403 unary_term { $$ = $1; } 1404 | unary_operator unary_term { $$ = $2; $$.fValue *= $1; } 1405 | STRING maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; } 1406 | IDENT maybe_space { 1407 $$.id = cssValueKeywordID($1); 1408 $$.unit = CSSPrimitiveValue::CSS_IDENT; 1409 $$.string = $1; 1410 } 1411 /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */ 1412 | DIMEN maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; } 1413 | unary_operator DIMEN maybe_space { $$.id = 0; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; } 1414 | URI maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; } 1415 | UNICODERANGE maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_UNICODE_RANGE; } 1416 | HEX maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } 1417 | '#' maybe_space { $$.id = 0; $$.string = CSSParserString(); $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } /* Handle error case: "color: #;" */ 1418 /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */ 1419 | function { 1420 $$ = $1; 1421 } 1422 | calc_function { 1423 $$ = $1; 1424 } 1425 | min_or_max_function { 1426 $$ = $1; 1427 } 1428 | '%' maybe_space { /* Handle width: %; */ 1429 $$.id = 0; $$.unit = 0; 1430 } 1431 ; 1432 1433 unary_term: 1434 INTEGER maybe_space { $$.id = 0; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } 1435 | FLOATTOKEN maybe_space { $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; } 1436 | PERCENTAGE maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; } 1437 | PXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; } 1438 | CMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; } 1439 | MMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; } 1440 | INS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; } 1441 | PTS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; } 1442 | PCS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; } 1443 | DEGS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; } 1444 | RADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; } 1445 | GRADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; } 1446 | TURNS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_TURN; } 1447 | MSECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; } 1448 | SECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; } 1449 | HERTZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; } 1450 | KHERTZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; } 1451 | EMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; } 1452 | QEMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSParserValue::Q_EMS; } 1453 | EXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; } 1454 | REMS maybe_space { 1455 $$.id = 0; 1456 $$.fValue = $1; 1457 $$.unit = CSSPrimitiveValue::CSS_REMS; 1458 CSSParser* p = static_cast<CSSParser*>(parser); 1459 if (Document* doc = p->document()) 1460 doc->setUsesRemUnits(true); 1461 } 1462 ; 1463 1464 function: 1465 FUNCTION maybe_space expr ')' maybe_space { 1466 CSSParser* p = static_cast<CSSParser*>(parser); 1467 CSSParserFunction* f = p->createFloatingFunction(); 1468 f->name = $1; 1469 f->args = p->sinkFloatingValueList($3); 1470 $$.id = 0; 1471 $$.unit = CSSParserValue::Function; 1472 $$.function = f; 1473 } | 1474 FUNCTION maybe_space error { 1475 CSSParser* p = static_cast<CSSParser*>(parser); 1476 CSSParserFunction* f = p->createFloatingFunction(); 1477 f->name = $1; 1478 f->args = 0; 1479 $$.id = 0; 1480 $$.unit = CSSParserValue::Function; 1481 $$.function = f; 1482 } 1483 ; 1484 1485 calc_func_term: 1486 unary_term { $$ = $1; } 1487 | unary_operator unary_term { $$ = $2; $$.fValue *= $1; } 1488 ; 1489 1490 calc_func_operator: 1491 '+' WHITESPACE { 1492 $$ = '+'; 1493 } 1494 | '-' WHITESPACE { 1495 $$ = '-'; 1496 } 1497 | '*' maybe_space { 1498 $$ = '*'; 1499 } 1500 | '/' maybe_space { 1501 $$ = '/'; 1502 } 1503 | IDENT maybe_space { 1504 if (equalIgnoringCase("mod", $1.characters, $1.length)) 1505 $$ = '%'; 1506 else 1507 $$ = 0; 1508 } 1509 ; 1510 1511 calc_func_paren_expr: 1512 '(' maybe_space calc_func_expr maybe_space ')' maybe_space { 1513 if ($3) { 1514 $$ = $3; 1515 CSSParserValue v; 1516 v.id = 0; 1517 v.unit = CSSParserValue::Operator; 1518 v.iValue = '('; 1519 $$->insertValueAt(0, v); 1520 v.iValue = ')'; 1521 $$->addValue(v); 1522 } else 1523 $$ = 0; 1524 } 1525 1526 calc_func_expr: 1527 calc_func_term maybe_space { 1528 CSSParser* p = static_cast<CSSParser*>(parser); 1529 $$ = p->createFloatingValueList(); 1530 $$->addValue(p->sinkFloatingValue($1)); 1531 } 1532 | calc_func_expr calc_func_operator calc_func_term { 1533 CSSParser* p = static_cast<CSSParser*>(parser); 1534 if ($1 && $2) { 1535 $$ = $1; 1536 CSSParserValue v; 1537 v.id = 0; 1538 v.unit = CSSParserValue::Operator; 1539 v.iValue = $2; 1540 $$->addValue(v); 1541 $$->addValue(p->sinkFloatingValue($3)); 1542 } else 1543 $$ = 0; 1544 1545 } 1546 | calc_func_expr calc_func_operator calc_func_paren_expr { 1547 if ($1 && $2 && $3) { 1548 $$ = $1; 1549 CSSParserValue v; 1550 v.id = 0; 1551 v.unit = CSSParserValue::Operator; 1552 v.iValue = $2; 1553 $$->addValue(v); 1554 $$->extend(*($3)); 1555 } else 1556 $$ = 0; 1557 } 1558 | calc_func_paren_expr 1559 | calc_func_expr error { 1560 $$ = 0; 1561 } 1562 ; 1563 1564 calc_func_expr_list: 1565 calc_func_expr { 1566 $$ = $1; 1567 } 1568 | calc_func_expr_list ',' maybe_space calc_func_expr { 1569 if ($1 && $4) { 1570 $$ = $1; 1571 CSSParserValue v; 1572 v.id = 0; 1573 v.unit = CSSParserValue::Operator; 1574 v.iValue = ','; 1575 $$->addValue(v); 1576 $$->extend(*($4)); 1577 } else 1578 $$ = 0; 1579 } 1580 1581 1582 calc_function: 1583 CALCFUNCTION maybe_space calc_func_expr ')' maybe_space { 1584 CSSParser* p = static_cast<CSSParser*>(parser); 1585 CSSParserFunction* f = p->createFloatingFunction(); 1586 f->name = $1; 1587 f->args = p->sinkFloatingValueList($3); 1588 $$.id = 0; 1589 $$.unit = CSSParserValue::Function; 1590 $$.function = f; 1591 } 1592 | CALCFUNCTION maybe_space error { 1593 YYERROR; 1594 } 1595 ; 1596 1597 1598 min_or_max: 1599 MINFUNCTION { 1600 $$ = $1; 1601 } 1602 | MAXFUNCTION { 1603 $$ = $1; 1604 } 1605 ; 1606 1607 min_or_max_function: 1608 min_or_max maybe_space calc_func_expr_list ')' maybe_space { 1609 CSSParser* p = static_cast<CSSParser*>(parser); 1610 CSSParserFunction* f = p->createFloatingFunction(); 1611 f->name = $1; 1612 f->args = p->sinkFloatingValueList($3); 1613 $$.id = 0; 1614 $$.unit = CSSParserValue::Function; 1615 $$.function = f; 1616 } 1617 | min_or_max maybe_space error { 1618 YYERROR; 1619 } 1620 ; 1621 1622 /* error handling rules */ 1623 1624 save_block: 1625 closing_brace { 1626 $$ = 0; 1627 } 1628 | error closing_brace { 1629 $$ = 0; 1630 } 1631 ; 1632 1633 invalid_at: 1634 ATKEYWORD error invalid_block { 1635 $$ = 0; 1636 } 1637 | ATKEYWORD error ';' { 1638 $$ = 0; 1639 } 1640 ; 1641 1642 invalid_rule: 1643 error invalid_block { 1644 $$ = 0; 1645 } 1646 1647 /* 1648 Seems like the two rules below are trying too much and violating 1649 http://www.hixie.ch/tests/evil/mixed/csserrorhandling.html 1650 1651 | error ';' { 1652 $$ = 0; 1653 } 1654 | error '}' { 1655 $$ = 0; 1656 } 1657 */ 1658 ; 1659 1660 invalid_block: 1661 '{' error invalid_block_list error closing_brace { 1662 static_cast<CSSParser*>(parser)->invalidBlockHit(); 1663 } 1664 | '{' error closing_brace { 1665 static_cast<CSSParser*>(parser)->invalidBlockHit(); 1666 } 1667 ; 1668 1669 invalid_block_list: 1670 invalid_block 1671 | invalid_block_list error invalid_block 1672 ; 1673 1674 %% 1675