OSDN Git Service

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