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