4f95fa032d196bbb491f91d88791e25dbcade9cc
[WebKit-https.git] / WebCore / css / CSSGrammar.y
1 %{
2
3 /*
4  *  This file is part of the KDE libraries
5  *  Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org)
6  *  Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
7  *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "config.h"
26
27 #include "CSSMediaRule.h"
28 #include "CSSPrimitiveValue.h"
29 #include "CSSRule.h"
30 #include "CSSRuleList.h"
31 #include "CSSSelector.h"
32 #include "CSSStyleSheet.h"
33 #include "Document.h"
34 #include "HTMLNames.h"
35 #include "MediaList.h"
36 #include "MediaQuery.h"
37 #include "MediaQueryExp.h"
38 #include "PlatformString.h"
39 #include "cssparser.h"
40 #include <assert.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #ifdef SVG_SUPPORT
45 #include "ksvgcssproperties.h"
46 #include "ksvgcssvalues.h"
47 #endif
48
49 using namespace WebCore;
50 using namespace HTMLNames;
51
52 // The following file defines the function
53 //     const struct props *findProp(const char *word, int len)
54 //
55 // with 'props->id' a CSS property in the range from CSS_PROP_MIN to
56 // (and including) CSS_PROP_TOTAL-1
57
58 #include "CSSPropertyNames.c"
59 #include "CSSValueKeywords.c"
60
61 namespace WebCore {
62
63 int getPropertyID(const char* tagStr, int len)
64 {
65     DeprecatedString prop;
66
67     if (len && tagStr[0] == '-') {
68         prop = DeprecatedString(tagStr, len);
69         if (prop.startsWith("-apple-")) {
70             prop = "-webkit-" + prop.mid(7);
71             tagStr = prop.ascii();
72             len++;
73         } else if (prop.startsWith("-khtml-")) {
74             prop = "-webkit-" + prop.mid(7);
75             len++;
76             tagStr = prop.ascii();
77         }
78         
79         // Honor the use of old-style opacity (for Safari 1.1).
80         if (prop == "-webkit-opacity") {
81             const char * const opacity = "opacity";
82             tagStr = opacity;
83             len = strlen(opacity);
84         }
85     }
86
87     const struct props* propsPtr = findProp(tagStr, len);
88     if (!propsPtr)
89         return 0;
90
91     return propsPtr->id;
92 }
93
94 }
95
96 static inline int getValueID(const char* tagStr, int len)
97 {
98     DeprecatedString prop;
99     if (len && tagStr[0] == '-') {
100         prop = DeprecatedString(tagStr, len);
101         if (prop.startsWith("-apple-")) {
102             prop = "-webkit-" + prop.mid(7);
103             tagStr = prop.ascii();
104             len++;
105         } else if (prop.startsWith("-khtml-")) {
106             prop = "-webkit-" + prop.mid(7);
107             len++;
108             tagStr = prop.ascii();
109         }
110     }
111
112     const struct css_value *val = findValue(tagStr, len);
113     if (!val)
114         return 0;
115
116     return val->id;
117 }
118
119 #define YYENABLE_NLS 0
120 #define YYLTYPE_IS_TRIVIAL 1
121 #define YYMAXDEPTH 10000
122 #define YYDEBUG 0
123 #define YYPARSE_PARAM parser
124
125 %}
126
127 %pure_parser
128
129 %union {
130     CSSRule* rule;
131     CSSSelector* selector;
132     bool ok;
133     MediaList *mediaList;
134     CSSMediaRule* mediaRule;
135     CSSRuleList* ruleList;
136     ParseString string;
137     float val;
138     int prop_id;
139     int attribute;
140     CSSSelector::Relation relation;
141     bool b;
142     int i;
143     char tok;
144     Value value;
145     ValueList* valueList;
146
147     MediaQuery* mediaQuery;
148     MediaQueryExp* mediaQueryExp;
149     Vector<MediaQueryExp*>* mediaQueryExpList;
150     MediaQuery::Restrictor mediaQueryRestrictor;
151 }
152
153 %{
154
155 static inline int cssyyerror(const char *) { return 1; }
156 static int cssyylex(YYSTYPE *yylval) { return CSSParser::current()->lex(yylval); }
157
158 %}
159
160 //%expect 37
161
162 %left UNIMPORTANT_TOK
163
164 %token WHITESPACE SGML_CD
165
166 %token INCLUDES
167 %token DASHMATCH
168 %token BEGINSWITH
169 %token ENDSWITH
170 %token CONTAINS
171
172 %token <string> STRING
173
174 %right <string> IDENT
175
176 %nonassoc <string> HASH
177 %nonassoc ':'
178 %nonassoc '.'
179 %nonassoc '['
180 %nonassoc <string> '*'
181 %nonassoc error
182 %left '|'
183
184 %token IMPORT_SYM
185 %token PAGE_SYM
186 %token MEDIA_SYM
187 %token FONT_FACE_SYM
188 %token CHARSET_SYM
189 %token NAMESPACE_SYM
190 %token WEBKIT_RULE_SYM
191 %token WEBKIT_DECLS_SYM
192 %token WEBKIT_VALUE_SYM
193 %token WEBKIT_MEDIAQUERY_SYM
194
195 %token IMPORTANT_SYM
196 %token MEDIA_ONLY
197 %token MEDIA_NOT
198 %token MEDIA_AND
199
200 %token <val> QEMS
201 %token <val> EMS
202 %token <val> EXS
203 %token <val> PXS
204 %token <val> CMS
205 %token <val> MMS
206 %token <val> INS
207 %token <val> PTS
208 %token <val> PCS
209 %token <val> DEGS
210 %token <val> RADS
211 %token <val> GRADS
212 %token <val> MSECS
213 %token <val> SECS
214 %token <val> HERZ
215 %token <val> KHERZ
216 %token <string> DIMEN
217 %token <val> PERCENTAGE
218 %token <val> FLOAT
219 %token <val> INTEGER
220
221 %token <string> URI
222 %token <string> FUNCTION
223 %token <string> NOTFUNCTION
224
225 %token <string> UNICODERANGE
226
227 %type <relation> combinator
228
229 %type <rule> charset
230 %type <rule> ruleset
231 %type <rule> media
232 %type <rule> import
233 %type <rule> page
234 %type <rule> font_face
235 %type <rule> invalid_rule
236 %type <rule> invalid_at
237 %type <rule> invalid_import
238 %type <rule> rule
239
240 %type <string> maybe_ns_prefix
241
242 %type <string> namespace_selector
243
244 %type <string> string_or_uri
245 %type <string> ident_or_string
246 %type <string> medium
247 %type <string> hexcolor
248
249 %type <string> media_feature
250 %type <mediaList> media_list
251 %type <mediaList> maybe_media_list
252 %type <mediaQuery> media_query
253 %type <mediaQueryRestrictor> maybe_media_restrictor
254 %type <valueList> maybe_media_value
255 %type <mediaQueryExp> media_query_exp
256 %type <mediaQueryExpList> media_query_exp_list
257 %type <mediaQueryExpList> maybe_media_query_exp_list
258
259 %type <ruleList> ruleset_list
260
261 %type <prop_id> property
262
263 %type <selector> specifier
264 %type <selector> specifier_list
265 %type <selector> simple_selector
266 %type <selector> selector
267 %type <selector> selector_list
268 %type <selector> class
269 %type <selector> attrib
270 %type <selector> pseudo
271
272 %type <ok> declaration_list
273 %type <ok> decl_list
274 %type <ok> declaration
275
276 %type <b> prio
277
278 %type <i> match
279 %type <i> unary_operator
280 %type <tok> operator
281
282 %type <valueList> expr
283 %type <value> term
284 %type <value> unary_term
285 %type <value> function
286
287 %type <string> element_name
288 %type <string> attr_name
289
290 %%
291
292 stylesheet:
293     maybe_charset maybe_sgml import_list namespace_list rule_list
294   | webkit_rule maybe_space
295   | webkit_decls maybe_space
296   | webkit_value maybe_space
297   | webkit_mediaquery maybe_space
298   ;
299
300 webkit_rule:
301     WEBKIT_RULE_SYM '{' maybe_space ruleset maybe_space '}' {
302         static_cast<CSSParser*>(parser)->rule = $4;
303     }
304 ;
305
306 webkit_decls:
307     WEBKIT_DECLS_SYM '{' maybe_space declaration_list '}' {
308         /* can be empty */
309     }
310 ;
311
312 webkit_value:
313     WEBKIT_VALUE_SYM '{' maybe_space expr '}' {
314         CSSParser *p = static_cast<CSSParser *>(parser);
315         if ($4) {
316             p->valueList = p->sinkFloatingValueList($4);
317             int oldParsedProperties = p->numParsedProperties;
318             if (!p->parseValue(p->id, p->important))
319                 p->rollbackLastProperties(p->numParsedProperties - oldParsedProperties);
320             delete p->valueList;
321             p->valueList = 0;
322         }
323     }
324 ;
325
326 webkit_mediaquery:
327      WEBKIT_MEDIAQUERY_SYM WHITESPACE maybe_space media_query '}' {
328          CSSParser* p = static_cast<CSSParser*>(parser);
329          p->mediaQuery = p->sinkFloatingMediaQuery($4);
330      }
331 ;
332
333 maybe_space:
334     /* empty */ %prec UNIMPORTANT_TOK
335   | maybe_space WHITESPACE
336   ;
337
338 maybe_sgml:
339     /* empty */
340   | maybe_sgml SGML_CD
341   | maybe_sgml WHITESPACE
342   ;
343
344 maybe_charset:
345    /* empty */
346   | charset {
347   }
348 ;
349
350 charset:
351   CHARSET_SYM maybe_space STRING maybe_space ';' {
352      CSSParser* p = static_cast<CSSParser*>(parser);
353      $$ = static_cast<CSSParser *>(parser)->createCharsetRule($3);
354      if ($$ && p->styleElement && p->styleElement->isCSSStyleSheet())
355          p->styleElement->append($$);
356   }
357   | CHARSET_SYM error invalid_block {
358   }
359   | CHARSET_SYM error ';' {
360   }
361 ;
362
363 import_list:
364  /* empty */
365  | import_list import maybe_sgml {
366      CSSParser* p = static_cast<CSSParser*>(parser);
367      if ($2 && p->styleElement && p->styleElement->isCSSStyleSheet())
368          p->styleElement->append($2);
369  }
370  ;
371
372 namespace_list:
373 /* empty */
374 | namespace_list namespace maybe_sgml
375 ;
376
377 rule_list:
378    /* empty */
379  | rule_list rule maybe_sgml {
380      CSSParser* p = static_cast<CSSParser*>(parser);
381      if ($2 && p->styleElement && p->styleElement->isCSSStyleSheet())
382          p->styleElement->append($2);
383  }
384  ;
385
386 rule:
387     ruleset
388   | media
389   | page
390   | font_face
391   | invalid_rule
392   | invalid_at
393   | invalid_import
394     ;
395
396 import:
397     IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list ';' {
398         $$ = static_cast<CSSParser *>(parser)->createImportRule($3, $5);
399     }
400   | IMPORT_SYM error invalid_block {
401         $$ = 0;
402     }
403   | IMPORT_SYM error ';' {
404         $$ = 0;
405     }
406   ;
407
408 namespace:
409 NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space ';' {
410     CSSParser *p = static_cast<CSSParser *>(parser);
411     if (p->styleElement && p->styleElement->isCSSStyleSheet())
412         static_cast<CSSStyleSheet*>(p->styleElement)->addNamespace(p, atomicString($3), atomicString($4));
413 }
414 | NAMESPACE_SYM error invalid_block
415 | NAMESPACE_SYM error ';'
416 ;
417
418 maybe_ns_prefix:
419 /* empty */ { $$.characters = 0; }
420 | IDENT WHITESPACE { $$ = $1; }
421 ;
422
423 string_or_uri:
424 STRING
425 | URI
426 ;
427
428 media_feature:
429     IDENT maybe_space {
430         $$ = $1;
431     }
432     ;
433
434 maybe_media_value:
435     /*empty*/ {
436         $$ = 0;
437     }
438     | ':' maybe_space expr maybe_space {
439         $$ = $3;
440     }
441     ;
442
443 media_query_exp:
444     MEDIA_AND maybe_space '(' maybe_space media_feature maybe_space maybe_media_value ')' maybe_space {
445         $5.lower();
446         $$ = static_cast<CSSParser*>(parser)->createFloatingMediaQueryExp(atomicString($5), $7);
447     }
448     ;
449
450 media_query_exp_list:
451     media_query_exp {
452       CSSParser* p = static_cast<CSSParser*>(parser);
453       $$ = p->createFloatingMediaQueryExpList();
454       $$->append(p->sinkFloatingMediaQueryExp($1));
455     }
456     | media_query_exp_list media_query_exp {
457       $$ = $1;
458       $$->append(static_cast<CSSParser*>(parser)->sinkFloatingMediaQueryExp($2));
459     }
460     ;
461
462 maybe_media_query_exp_list:
463     /*empty*/ {
464         $$ = static_cast<CSSParser*>(parser)->createFloatingMediaQueryExpList();
465     }
466     | media_query_exp_list
467     ;
468
469 maybe_media_restrictor:
470     /*empty*/ {
471         $$ = MediaQuery::None;
472     }
473     | MEDIA_ONLY {
474         $$ = MediaQuery::Only;
475     }
476     | MEDIA_NOT {
477         $$ = MediaQuery::Not;
478     }
479     ;
480
481 media_query:
482     maybe_media_restrictor maybe_space medium maybe_media_query_exp_list {
483         CSSParser* p = static_cast<CSSParser*>(parser);
484         $3.lower();
485         $$ = p->createFloatingMediaQuery($1, domString($3), p->sinkFloatingMediaQueryExpList($4));
486     }
487     ;
488
489 maybe_media_list:
490      /* empty */ {
491         $$ = static_cast<CSSParser*>(parser)->createMediaList();
492      }
493      | media_list
494      ;
495
496 media_list:
497     media_query {
498         CSSParser* p = static_cast<CSSParser*>(parser);
499         $$ = p->createMediaList();
500         $$->appendMediaQuery(p->sinkFloatingMediaQuery($1));
501     }
502     | media_list ',' maybe_space media_query {
503         $$ = $1;
504         if ($$)
505             $$->appendMediaQuery(static_cast<CSSParser*>(parser)->sinkFloatingMediaQuery($4));
506     }
507     | media_list error {
508         $$ = 0;
509     }
510     ;
511
512 media:
513     MEDIA_SYM maybe_space media_list '{' maybe_space ruleset_list '}' {
514         $$ = static_cast<CSSParser*>(parser)->createMediaRule($3, $6);
515     }
516     | MEDIA_SYM maybe_space '{' maybe_space ruleset_list '}' {
517         $$ = static_cast<CSSParser*>(parser)->createMediaRule(0, $5);
518     }
519     ;
520
521 ruleset_list:
522     /* empty */ { $$ = 0; }
523     | ruleset_list ruleset maybe_space {
524         $$ = $1;
525         if ($2) {
526             if (!$$)
527                 $$ = static_cast<CSSParser*>(parser)->createRuleList();
528             $$->append($2);
529         }
530     }
531     ;
532
533 medium:
534   IDENT maybe_space {
535       $$ = $1;
536   }
537   ;
538
539 /*
540 page:
541     PAGE_SYM maybe_space IDENT? pseudo_page? maybe_space
542     '{' maybe_space declaration [ ';' maybe_space declaration ]* '}' maybe_space
543   ;
544
545 pseudo_page
546   : ':' IDENT
547   ;
548
549 font_face
550   : FONT_FACE_SYM maybe_space
551     '{' maybe_space declaration [ ';' maybe_space declaration ]* '}' maybe_space
552   ;
553 */
554
555 page:
556     PAGE_SYM error invalid_block {
557       $$ = 0;
558     }
559   | PAGE_SYM error ';' {
560       $$ = 0;
561     }
562     ;
563
564 font_face:
565     FONT_FACE_SYM error invalid_block {
566       $$ = 0;
567     }
568   | FONT_FACE_SYM error ';' {
569       $$ = 0;
570     }
571 ;
572
573 combinator:
574     '+' maybe_space { $$ = CSSSelector::DirectAdjacent; }
575   | '~' maybe_space { $$ = CSSSelector::IndirectAdjacent; }
576   | '>' maybe_space { $$ = CSSSelector::Child; }
577   | /* empty */ { $$ = CSSSelector::Descendant; }
578   ;
579
580 unary_operator:
581     '-' { $$ = -1; }
582   | '+' { $$ = 1; }
583   ;
584
585 ruleset:
586     selector_list '{' maybe_space declaration_list '}' {
587         $$ = static_cast<CSSParser*>(parser)->createStyleRule($1);
588     }
589   ;
590
591 selector_list:
592     selector %prec UNIMPORTANT_TOK {
593         $$ = $1;
594     }
595     | selector_list ',' maybe_space selector %prec UNIMPORTANT_TOK {
596         if ($1 && $4) {
597             CSSParser* p = static_cast<CSSParser*>(parser);
598             $$ = $1;
599             $$->append(p->sinkFloatingSelector($4));
600         } else {
601             $$ = 0;
602         }
603     }
604   | selector_list error {
605         $$ = 0;
606     }
607    ;
608
609 selector:
610     simple_selector {
611         $$ = $1;
612     }
613     | selector combinator simple_selector {
614         $$ = $3;
615         if (!$1) {
616             $$ = 0;
617         }
618         else if ($$) {
619             CSSParser* p = static_cast<CSSParser*>(parser);
620             CSSSelector* end = $$;
621             while (end->tagHistory)
622                 end = end->tagHistory;
623             end->m_relation = $2;
624             end->tagHistory = p->sinkFloatingSelector($1);
625             if ($2 == CSSSelector::Descendant || $2 == CSSSelector::Child) {
626                 if (Document* doc = p->document())
627                     doc->setUsesDescendantRules(true);
628             } else if ($2 == CSSSelector::DirectAdjacent || $2 == CSSSelector::IndirectAdjacent) {
629                 if (Document* doc = p->document())
630                     doc->setUsesSiblingRules(true);
631             }
632         }
633     }
634     | selector error {
635         $$ = 0;
636     }
637     ;
638
639 namespace_selector:
640     /* empty */ '|' { $$.characters = 0; $$.length = 0; }
641     | '*' '|' { static UChar star = '*'; $$.characters = &star; $$.length = 1; }
642     | IDENT '|' { $$ = $1; }
643 ;
644
645 simple_selector:
646     element_name maybe_space {
647         CSSParser *p = static_cast<CSSParser *>(parser);
648         $$ = p->createFloatingSelector();
649         $$->tag = QualifiedName(nullAtom, atomicString($1), p->defaultNamespace);
650     }
651     | element_name specifier_list maybe_space {
652         $$ = $2;
653         if ($$) {
654             CSSParser *p = static_cast<CSSParser *>(parser);
655             $$->tag = QualifiedName(nullAtom, atomicString($1), p->defaultNamespace);
656         }
657     }
658     | specifier_list maybe_space {
659         $$ = $1;
660         CSSParser *p = static_cast<CSSParser *>(parser);
661         if ($$ && p->defaultNamespace != starAtom)
662             $$->tag = QualifiedName(nullAtom, starAtom, p->defaultNamespace);
663     }
664     | namespace_selector element_name maybe_space {
665         AtomicString namespacePrefix = atomicString($1);
666         CSSParser *p = static_cast<CSSParser *>(parser);
667         $$ = p->createFloatingSelector();
668         if (p->styleElement && p->styleElement->isCSSStyleSheet())
669             $$->tag = QualifiedName(namespacePrefix,
670                                     atomicString($2),
671                                     static_cast<CSSStyleSheet*>(p->styleElement)->determineNamespace(namespacePrefix));
672         else // FIXME: Shouldn't this case be an error?
673             $$->tag = QualifiedName(nullAtom, atomicString($2), p->defaultNamespace);
674     }
675     | namespace_selector element_name specifier_list maybe_space {
676         $$ = $3;
677         if ($$) {
678             AtomicString namespacePrefix = atomicString($1);
679             CSSParser *p = static_cast<CSSParser *>(parser);
680             if (p->styleElement && p->styleElement->isCSSStyleSheet())
681                 $$->tag = QualifiedName(namespacePrefix,
682                                         atomicString($2),
683                                         static_cast<CSSStyleSheet*>(p->styleElement)->determineNamespace(namespacePrefix));
684             else // FIXME: Shouldn't this case be an error?
685                 $$->tag = QualifiedName(nullAtom, atomicString($2), p->defaultNamespace);
686         }
687     }
688     | namespace_selector specifier_list maybe_space {
689         $$ = $2;
690         if ($$) {
691             AtomicString namespacePrefix = atomicString($1);
692             CSSParser *p = static_cast<CSSParser *>(parser);
693             if (p->styleElement && p->styleElement->isCSSStyleSheet())
694                 $$->tag = QualifiedName(namespacePrefix,
695                                         starAtom,
696                                         static_cast<CSSStyleSheet*>(p->styleElement)->determineNamespace(namespacePrefix));
697         }
698     }
699   ;
700
701 element_name:
702     IDENT {
703         ParseString& str = $1;
704         CSSParser *p = static_cast<CSSParser *>(parser);
705         Document *doc = p->document();
706         if (doc && doc->isHTMLDocument())
707             str.lower();
708         $$ = str;
709     }
710     | '*' {
711         static UChar star = '*';
712         $$.characters = &star;
713         $$.length = 1;
714     }
715   ;
716
717 specifier_list:
718     specifier {
719         $$ = $1;
720     }
721     | specifier_list specifier {
722         $$ = $1;
723         if ($$) {
724             CSSParser* p = static_cast<CSSParser*>(parser);
725             CSSSelector* end = $1;
726             while (end->tagHistory)
727                 end = end->tagHistory;
728             end->m_relation = CSSSelector::SubSelector;
729             end->tagHistory = p->sinkFloatingSelector($2);
730         }
731     }
732     | specifier_list error {
733         $$ = 0;
734     }
735 ;
736
737 specifier:
738     HASH {
739         CSSParser *p = static_cast<CSSParser *>(parser);
740         $$ = p->createFloatingSelector();
741         $$->match = CSSSelector::Id;
742         if (!p->strict)
743             $1.lower();
744         $$->attr = idAttr;
745         $$->value = atomicString($1);
746     }
747   | class
748   | attrib
749   | pseudo
750     ;
751
752 class:
753     '.' IDENT {
754         CSSParser *p = static_cast<CSSParser *>(parser);
755         $$ = p->createFloatingSelector();
756         $$->match = CSSSelector::Class;
757         if (!p->strict)
758             $2.lower();
759         $$->attr = classAttr;
760         $$->value = atomicString($2);
761     }
762   ;
763
764 attr_name:
765     IDENT maybe_space {
766         ParseString& str = $1;
767         CSSParser *p = static_cast<CSSParser *>(parser);
768         Document *doc = p->document();
769         if (doc && doc->isHTMLDocument())
770             str.lower();
771         $$ = str;
772     }
773     ;
774
775 attrib:
776     '[' maybe_space attr_name ']' {
777         $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
778         $$->attr = QualifiedName(nullAtom, atomicString($3), nullAtom);
779         $$->match = CSSSelector::Set;
780     }
781     | '[' maybe_space attr_name match maybe_space ident_or_string maybe_space ']' {
782         $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
783         $$->attr = QualifiedName(nullAtom, atomicString($3), nullAtom);
784         $$->match = (CSSSelector::Match)$4;
785         $$->value = atomicString($6);
786     }
787     | '[' maybe_space namespace_selector attr_name ']' {
788         AtomicString namespacePrefix = atomicString($3);
789         CSSParser *p = static_cast<CSSParser *>(parser);
790         $$ = p->createFloatingSelector();
791         $$->attr = QualifiedName(namespacePrefix,
792                                  atomicString($4),
793                                  static_cast<CSSStyleSheet*>(p->styleElement)->determineNamespace(namespacePrefix));
794         $$->match = CSSSelector::Set;
795     }
796     | '[' maybe_space namespace_selector attr_name match maybe_space ident_or_string maybe_space ']' {
797         AtomicString namespacePrefix = atomicString($3);
798         CSSParser *p = static_cast<CSSParser *>(parser);
799         $$ = p->createFloatingSelector();
800         $$->attr = QualifiedName(namespacePrefix,
801                                  atomicString($4),
802                                  static_cast<CSSStyleSheet*>(p->styleElement)->determineNamespace(namespacePrefix));
803         $$->match = (CSSSelector::Match)$5;
804         $$->value = atomicString($7);
805     }
806   ;
807
808 match:
809     '=' {
810         $$ = CSSSelector::Exact;
811     }
812     | INCLUDES {
813         $$ = CSSSelector::List;
814     }
815     | DASHMATCH {
816         $$ = CSSSelector::Hyphen;
817     }
818     | BEGINSWITH {
819         $$ = CSSSelector::Begin;
820     }
821     | ENDSWITH {
822         $$ = CSSSelector::End;
823     }
824     | CONTAINS {
825         $$ = CSSSelector::Contain;
826     }
827     ;
828
829 ident_or_string:
830     IDENT
831   | STRING
832     ;
833
834 pseudo:
835     ':' IDENT {
836         $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
837         $$->match = CSSSelector::PseudoClass;
838         $2.lower();
839         $$->value = atomicString($2);
840         if ($$->value == "empty" || $$->value == "only-child" ||
841             $$->value == "first-child" || $$->value == "last-child") {
842             CSSParser *p = static_cast<CSSParser *>(parser);
843             Document *doc = p->document();
844             if (doc)
845                 doc->setUsesSiblingRules(true);
846         }
847     }
848     | ':' ':' IDENT {
849         $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
850         $$->match = CSSSelector::PseudoElement;
851         $3.lower();
852         $$->value = atomicString($3);
853     }
854     // used by :lang
855     | ':' FUNCTION IDENT ')' {
856         $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
857         $$->match = CSSSelector::PseudoClass;
858         $$->argument = atomicString($3);
859         $2.lower();
860         $$->value = atomicString($2);
861     }
862     // used by :not
863     | ':' NOTFUNCTION maybe_space simple_selector ')' {
864         CSSParser* p = static_cast<CSSParser*>(parser);
865         $$ = p->createFloatingSelector();
866         $$->match = CSSSelector::PseudoClass;
867         $$->simpleSelector = p->sinkFloatingSelector($4);
868         $2.lower();
869         $$->value = atomicString($2);
870     }
871   ;
872
873 declaration_list:
874     declaration {
875         $$ = $1;
876     }
877     | decl_list declaration {
878         $$ = $1;
879         if ( $2 )
880             $$ = $2;
881     }
882     | decl_list {
883         $$ = $1;
884     }
885     | error invalid_block_list error {
886         $$ = false;
887     }
888     | error {
889         $$ = false;
890     }
891     | decl_list error {
892         $$ = $1;
893     }
894     ;
895
896 decl_list:
897     declaration ';' maybe_space {
898         $$ = $1;
899     }
900     | declaration invalid_block_list ';' maybe_space {
901         $$ = false;
902     }
903     | error ';' maybe_space {
904         $$ = false;
905     }
906     | error invalid_block_list error ';' maybe_space {
907         $$ = false;
908     }
909     | decl_list declaration ';' maybe_space {
910         $$ = $1;
911         if ( $2 )
912             $$ = $2;
913     }
914     | decl_list error ';' maybe_space {
915         $$ = $1;
916     }
917     | decl_list error invalid_block_list error ';' maybe_space {
918         $$ = $1;
919     }
920     ;
921
922 declaration:
923     property ':' maybe_space expr prio {
924         $$ = false;
925         CSSParser *p = static_cast<CSSParser *>(parser);
926         if ($1 && $4) {
927             p->valueList = p->sinkFloatingValueList($4);
928             int oldParsedProperties = p->numParsedProperties;
929             $$ = p->parseValue($1, $5);
930             if (!$$)
931                 p->rollbackLastProperties(p->numParsedProperties - oldParsedProperties);
932             delete p->valueList;
933             p->valueList = 0;
934         }
935     }
936     |
937     property error {
938         $$ = false;
939     }
940     |
941     property ':' maybe_space error expr prio {
942         /* The default movable type template has letter-spacing: .none;  Handle this by looking for
943         error tokens at the start of an expr, recover the expr and then treat as an error, cleaning
944         up and deleting the shifted expr.  */
945         $$ = false;
946     }
947     |
948     IMPORTANT_SYM maybe_space {
949         /* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */
950         $$ = false;
951     }
952     |
953     property ':' maybe_space {
954         /* div { font-family: } Just reduce away this property with no value. */
955         $$ = false;
956     }
957   ;
958
959 property:
960     IDENT maybe_space {
961         $1.lower();
962         DeprecatedString str = deprecatedString($1);
963         const char* s = str.ascii();
964         int l = str.length();
965         $$ = getPropertyID(s, l);
966 #ifdef SVG_SUPPORT
967         if ($$ == 0)
968             $$ = SVG::getSVGCSSPropertyID(s, l);
969 #endif
970     }
971   ;
972
973 prio:
974     IMPORTANT_SYM maybe_space { $$ = true; }
975     | /* empty */ { $$ = false; }
976   ;
977
978 expr:
979     term {
980         CSSParser* p = static_cast<CSSParser*>(parser);
981         $$ = p->createFloatingValueList();
982         $$->addValue(p->sinkFloatingValue($1));
983     }
984     | expr operator term {
985         CSSParser* p = static_cast<CSSParser*>(parser);
986         $$ = $1;
987         if ($$) {
988             if ($2) {
989                 Value v;
990                 v.id = 0;
991                 v.unit = Value::Operator;
992                 v.iValue = $2;
993                 $$->addValue(v);
994             }
995             $$->addValue(p->sinkFloatingValue($3));
996         }
997     }
998     | expr error {
999         $$ = 0;
1000     }
1001   ;
1002
1003 operator:
1004     '/' maybe_space {
1005         $$ = '/';
1006     }
1007   | ',' maybe_space {
1008         $$ = ',';
1009     }
1010   | /* empty */ {
1011         $$ = 0;
1012   }
1013   ;
1014
1015 term:
1016   unary_term { $$ = $1; }
1017   | unary_operator unary_term { $$ = $2; $$.fValue *= $1; }
1018   | STRING maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; }
1019   | IDENT maybe_space {
1020       DeprecatedString str = deprecatedString($1);
1021       $$.id = getValueID(str.lower().latin1(), str.length());
1022 #ifdef SVG_SUPPORT
1023       if ($$.id == 0)
1024           $$.id = SVG::getSVGCSSValueID(str.lower().latin1(), str.length());
1025 #endif
1026       $$.unit = CSSPrimitiveValue::CSS_IDENT;
1027       $$.string = $1;
1028   }
1029   /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */
1030   | DIMEN maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION }
1031   | unary_operator DIMEN maybe_space { $$.id = 0; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION }
1032   | URI maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; }
1033   | UNICODERANGE maybe_space { $$.id = 0; $$.iValue = 0; $$.unit = CSSPrimitiveValue::CSS_UNKNOWN;/* ### */ }
1034   | hexcolor { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_RGBCOLOR; }
1035   | '#' maybe_space { $$.id = 0; $$.string = ParseString(); $$.unit = CSSPrimitiveValue::CSS_RGBCOLOR; } /* Handle error case: "color: #;" */
1036 /* ### according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
1037   | function {
1038       $$ = $1;
1039   }
1040   ;
1041
1042 unary_term:
1043   INTEGER maybe_space { $$.id = 0; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1044   | FLOAT maybe_space { $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1045   | PERCENTAGE maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; }
1046   | PXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; }
1047   | CMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; }
1048   | MMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; }
1049   | INS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; }
1050   | PTS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; }
1051   | PCS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; }
1052   | DEGS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; }
1053   | RADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; }
1054   | GRADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; }
1055   | MSECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; }
1056   | SECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; }
1057   | HERZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; }
1058   | KHERZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; }
1059   | EMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; }
1060   | QEMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = Value::Q_EMS; }
1061   | EXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; }
1062     ;
1063
1064
1065 function:
1066     FUNCTION maybe_space expr ')' maybe_space {
1067         CSSParser* p = static_cast<CSSParser*>(parser);
1068         Function* f = p->createFloatingFunction();
1069         f->name = $1;
1070         f->args = p->sinkFloatingValueList($3);
1071         $$.id = 0;
1072         $$.unit = Value::Function;
1073         $$.function = f;
1074     } |
1075     FUNCTION maybe_space error {
1076         CSSParser* p = static_cast<CSSParser*>(parser);
1077         Function* f = p->createFloatingFunction();
1078         f->name = $1;
1079         f->args = 0;
1080         $$.id = 0;
1081         $$.unit = Value::Function;
1082         $$.function = f;
1083   }
1084   ;
1085 /*
1086  * There is a constraint on the color that it must
1087  * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
1088  * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
1089  */
1090 hexcolor:
1091   HASH maybe_space { $$ = $1; }
1092   ;
1093
1094
1095 /* error handling rules */
1096
1097 invalid_at:
1098     '@' error invalid_block {
1099         $$ = 0;
1100     }
1101   | '@' error ';' {
1102         $$ = 0;
1103     }
1104     ;
1105
1106 invalid_import:
1107     import {
1108         $$ = 0;
1109     }
1110     ;
1111
1112 invalid_rule:
1113     error invalid_block {
1114         $$ = 0;
1115     }
1116 /*
1117   Seems like the two rules below are trying too much and violating
1118   http://www.hixie.ch/tests/evil/mixed/csserrorhandling.html
1119
1120   | error ';' {
1121         $$ = 0;
1122     }
1123   | error '}' {
1124         $$ = 0;
1125     }
1126 */
1127     ;
1128
1129 invalid_block:
1130     '{' error invalid_block_list error '}'
1131   | '{' error '}'
1132     ;
1133
1134 invalid_block_list:
1135     invalid_block
1136   | invalid_block_list error invalid_block
1137 ;
1138
1139 %%