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