OSDN Git Service

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