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