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