OSDN Git Service

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