• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
cssyyerror(const char *)88 static inline int cssyyerror(const char*)
89 {
90     return 1;
91 }
92 
cssyylex(YYSTYPE * yylval,void * parser)93 static int cssyylex(YYSTYPE* yylval, void* parser)
94 {
95     return static_cast<CSSParser*>(parser)->lex(yylval);
96 }
97 
98 %}
99 
100 %expect 50
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_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 WHITESPACE { $$ = $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 %%
1530