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