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