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