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