Home | History | Annotate | Download | only in css
      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 = &star; $$.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 = &star;
    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