OSDN Git Service

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