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 %}
     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 = &star; $$.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 = &star;
    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