Warning, /frameworks/khtml/src/css/parser.y is written in an unsupported language. File is not indexed.

0001 %{
0002 
0003 /*
0004  *  This file is part of the KDE libraries
0005  *  Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org)
0006  *  Copyright (c) 2003 Apple Computer
0007  *  Copyright (C) 2003 Dirk Mueller (mueller@kde.org)
0008  *  Copyright (C) 2008 Germain Garand (germain@ebooksfrance.org)
0009  *
0010  *  This library is free software; you can redistribute it and/or
0011  *  modify it under the terms of the GNU Lesser General Public
0012  *  License as published by the Free Software Foundation; either
0013  *  version 2 of the License, or (at your option) any later version.
0014  *
0015  *  This library is distributed in the hope that it will be useful,
0016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0018  *  Lesser General Public License for more details.
0019  *
0020  *  You should have received a copy of the GNU Lesser General Public
0021  *  License along with this library; if not, write to the Free Software
0022  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0023  *
0024  */
0025 
0026 #include <string.h>
0027 #include <stdlib.h>
0028 
0029 #include <dom/dom_string.h>
0030 #include <xml/dom_docimpl.h>
0031 #include <css/cssstyleselector.h>
0032 #include <css/css_ruleimpl.h>
0033 #include <css/css_stylesheetimpl.h>
0034 #include <css/css_valueimpl.h>
0035 #include <css/css_mediaquery.h>
0036 #include "cssparser.h"
0037 
0038 
0039 
0040 #include <assert.h>
0041 #include <QDebug>
0042 
0043 //#define CSS_DEBUG
0044 
0045 using namespace DOM;
0046 
0047 //
0048 // The following file defines the function
0049 //     const struct props *findProp(const char *word, int len)
0050 //
0051 // with 'props->id' a CSS property in the range from CSS_PROP_MIN to
0052 // (and including) CSS_PROP_TOTAL-1
0053 
0054 // Turn off gnu90 inlining to avoid linker errors
0055 #undef __GNUC_STDC_INLINE__
0056 #undef __GNUC_GNU_INLINE__
0057 #include "cssproperties.c"
0058 #include "cssvalues.c"
0059 
0060 int DOM::getPropertyID(const char *tagStr, int len)
0061 {
0062     { // HTML CSS Properties
0063         const struct css_prop *prop = findProp(tagStr, len);
0064         if (!prop) {
0065             return 0;
0066         }
0067 
0068         return prop->id;
0069     }
0070 }
0071 
0072 int DOM::getValueID(const char *tagStr, int len)
0073 {
0074     { // HTML CSS Values
0075         const struct css_value *val = findValue(tagStr, len);
0076         if (!val) {
0077             return 0;
0078         }
0079 
0080         return val->id;
0081     }
0082 }
0083 
0084 #define YYDEBUG 0
0085 #define YYMAXDEPTH 10000
0086 #define YYPARSE_PARAM parser
0087 #define YYENABLE_NLS 0
0088 #define YYLTYPE_IS_TRIVIAL 1
0089 %}
0090 
0091 %expect 41
0092 
0093 %pure_parser
0094 
0095 %union {
0096     CSSRuleImpl *rule;
0097     CSSSelector *selector;
0098     QList<CSSSelector *> *selectorList;
0099     bool ok;
0100     MediaListImpl *mediaList;
0101     CSSMediaRuleImpl *mediaRule;
0102     CSSRuleListImpl *ruleList;
0103     ParseString string;
0104     double val;
0105     int prop_id;
0106     unsigned int attribute;
0107     unsigned int element;
0108     CSSSelector::Relation relation;
0109     CSSSelector::Match match;
0110     bool b;
0111     char tok;
0112     Value value;
0113     ValueList *valueList;
0114 
0115     khtml::MediaQuery *mediaQuery;
0116     khtml::MediaQueryExp *mediaQueryExp;
0117     QList<khtml::MediaQueryExp *> *mediaQueryExpList;
0118     khtml::MediaQuery::Restrictor mediaQueryRestrictor;
0119 }
0120 
0121 %{
0122 
0123 static inline int cssyyerror(const char *x)
0124 {
0125 #ifdef CSS_DEBUG
0126     qDebug("%s", x);
0127 #else
0128     Q_UNUSED(x);
0129 #endif
0130     return 1;
0131 }
0132 
0133 static int cssyylex(YYSTYPE *yylval) {
0134     return CSSParser::current()->lex(yylval);
0135 }
0136 
0137 #define null 1
0138 
0139 %}
0140 
0141 %destructor { delete $$; $$ = 0; } maybe_media_value expr;
0142 %destructor { delete $$; $$ = 0; } maybe_media_list media_list;
0143 %destructor { delete $$; $$ = 0; } maybe_and_media_query_exp_list media_query_exp_list;
0144 %destructor { if ($$) qDeleteAll(*$$); delete $$; $$ = 0; } selector_list;
0145 %destructor { delete $$; $$ = 0; } ruleset_list;
0146 %destructor { delete $$; $$ = 0; } specifier specifier_list simple_selector simple_css3_selector selector class attrib pseudo;
0147 %destructor { if ($$.function) delete $$.function->args; delete $$.function; $$.function = 0; } function;
0148 
0149 %no-lines
0150 %verbose
0151 
0152 %left REDUCE
0153 
0154 %token S SGML_CD
0155 
0156 %token INCLUDES
0157 %token DASHMATCH
0158 %token BEGINSWITH
0159 %token ENDSWITH
0160 %token CONTAINS
0161 
0162 %token <string> STRING
0163 
0164 %right <string> IDENT
0165 
0166 %token <string> NTH
0167 
0168 %nonassoc <string> HASH
0169 %nonassoc <string> HEXCOLOR     
0170 %nonassoc ':'
0171 %nonassoc '.'
0172 %nonassoc '['
0173 %nonassoc '*'
0174 %nonassoc error
0175 %left '|'
0176 
0177 %left IMPORT_SYM
0178 %token PAGE_SYM
0179 %token MEDIA_SYM
0180 %token FONT_FACE_SYM
0181 %token CHARSET_SYM
0182 %token NAMESPACE_SYM
0183 %token KHTML_RULE_SYM
0184 %token KHTML_DECLS_SYM
0185 %token KHTML_VALUE_SYM
0186 %token KHTML_MEDIAQUERY_SYM
0187 %token KHTML_SELECTORS_SYM
0188 
0189 %token IMPORTANT_SYM
0190 %token MEDIA_ONLY
0191 %token MEDIA_NOT
0192 %token MEDIA_AND
0193 
0194 %token <val> QEMS
0195 %token <val> EMS
0196 %token <val> EXS
0197 %token <val> CHS
0198 %token <val> REMS
0199 %token <val> PXS
0200 %token <val> CMS
0201 %token <val> MMS
0202 %token <val> INS
0203 %token <val> PTS
0204 %token <val> PCS
0205 %token <val> DEGS
0206 %token <val> RADS
0207 %token <val> GRADS
0208 %token <val> MSECS
0209 %token <val> SECS
0210 %token <val> HERZ
0211 %token <val> KHERZ
0212 %token <val> DPI
0213 %token <val> DPCM
0214 %token <string> DIMEN
0215 %token <val> PERCENTAGE
0216 %token <val> FLOAT
0217 %token <val> INTEGER
0218 
0219 %token <string> URI
0220 %token <string> FUNCTION
0221 %token <string> NOTFUNCTION
0222 
0223 %token <string> UNICODERANGE
0224 
0225 %type <relation> combinator
0226 
0227 %type <rule> charset
0228 %type <rule> ruleset
0229 %type <rule> safe_ruleset
0230 %type <rule> ruleset_or_import_or_namespace
0231 %type <rule> media
0232 %type <rule> import
0233 %type <rule> page
0234 %type <rule> font_face
0235 %type <rule> invalid_rule
0236 %type <rule> namespace_rule
0237 %type <rule> invalid_at
0238 %type <rule> rule
0239 
0240 %type <string> namespace_selector
0241 
0242 %type <string> string_or_uri
0243 %type <string> ident_or_string
0244 %type <string> medium
0245 %type <string> hexcolor
0246 %type <string> maybe_ns_prefix
0247 
0248 %type <string> media_feature
0249 %type <mediaList> media_list
0250 %type <mediaList> maybe_media_list
0251 %type <mediaQuery> media_query
0252 %type <mediaQueryRestrictor> maybe_media_restrictor
0253 %type <valueList> maybe_media_value
0254 %type <mediaQueryExp> media_query_exp
0255 %type <mediaQueryExpList> media_query_exp_list
0256 %type <mediaQueryExpList> maybe_and_media_query_exp_list
0257 
0258 %type <ruleList> ruleset_list
0259 
0260 %type <prop_id> property
0261 
0262 %type <selector> specifier
0263 %type <selector> specifier_list
0264 %type <selector> simple_selector
0265 %type <selector> simple_css3_selector
0266 %type <selector> selector
0267 %type <selectorList> selector_list
0268 %type <selector> class
0269 %type <selector> attrib
0270 %type <selector> pseudo
0271 
0272 %type <ok> declaration_block
0273 %type <ok> declaration_list
0274 %type <ok> declaration
0275 
0276 %type <b> prio
0277 
0278 %type <match> match
0279 %type <val> unary_operator
0280 %type <tok> operator
0281 
0282 %type <valueList> expr
0283 %type <value> term
0284 %type <value> unary_term
0285 %type <value> function
0286 
0287 %type <element> element_name
0288 
0289 %type <attribute> attrib_id
0290 
0291 %%
0292 
0293 stylesheet:
0294     maybe_space maybe_charset maybe_sgml import_list namespace_list rule_list
0295   | khtml_rule maybe_space
0296   | khtml_decls maybe_space
0297   | khtml_value maybe_space
0298   | khtml_mediaquery maybe_space
0299   | khtml_selectors maybe_space
0300   ;
0301 
0302 ruleset_or_import_or_namespace:
0303     ruleset |
0304     import  |
0305     namespace_rule
0306 ;
0307 
0308 khtml_rule:
0309     KHTML_RULE_SYM '{' maybe_space ruleset_or_import_or_namespace maybe_space '}' {
0310         CSSParser *p = static_cast<CSSParser *>(parser);
0311         p->rule = $4;
0312     }
0313 ;
0314 
0315 khtml_decls:
0316     KHTML_DECLS_SYM declaration_block {
0317         /* can be empty */
0318     }
0319 ;
0320 
0321 khtml_value:
0322     KHTML_VALUE_SYM '{' maybe_space expr '}' {
0323         CSSParser *p = static_cast<CSSParser *>(parser);
0324         if ( $4 ) {
0325             p->valueList = $4;
0326 #ifdef CSS_DEBUG
0327             qDebug() << "   got property for " << p->id <<
0328                 (p->important?" important":"");
0329             bool ok =
0330 #endif
0331                 p->parseValue( p->id, p->important );
0332 #ifdef CSS_DEBUG
0333             if ( !ok )
0334                 qDebug() << "     couldn't parse value!";
0335 #endif
0336         }
0337 #ifdef CSS_DEBUG
0338         else
0339             qDebug() << "     no value found!";
0340 #endif
0341         delete p->valueList;
0342         p->valueList = 0;
0343     }
0344 ;
0345 
0346 khtml_selectors:
0347         KHTML_SELECTORS_SYM '{' maybe_space selector_list '}' {
0348                 CSSParser *p = static_cast<CSSParser *>(parser);
0349                 if ($4) {
0350                         p->selectors = *$4;
0351                         delete $4;
0352                         $4 = 0;
0353                 } else
0354                         p->selectors.clear(); // parse error
0355         }
0356 ;
0357 
0358 khtml_mediaquery:
0359      KHTML_MEDIAQUERY_SYM S maybe_space media_query '}' {
0360          CSSParser *p = static_cast<CSSParser *>(parser);
0361          p->mediaQuery = $4;
0362      }
0363 ;
0364 
0365 maybe_plus:
0366     /* empty */
0367   | '+'
0368   ;
0369 
0370 maybe_space:
0371     /* empty */ %prec REDUCE
0372   | maybe_space S
0373   ;
0374 
0375 maybe_sgml:
0376     /* empty */
0377   | maybe_sgml SGML_CD
0378   | maybe_sgml S
0379   ;
0380 
0381 maybe_charset:
0382    /* empty */
0383   | charset
0384  ;
0385 charset:
0386   CHARSET_SYM maybe_space STRING maybe_space ';' {
0387 #ifdef CSS_DEBUG
0388      qDebug() << "charset rule: " << qString($3);
0389 #endif
0390      CSSParser* p = static_cast<CSSParser*>(parser);
0391      if (p->styleElement && p->styleElement->isCSSStyleSheet()) {
0392          p->styleElement->append( new CSSCharsetRuleImpl(p->styleElement, domString($3)) );
0393      }
0394  }
0395   | CHARSET_SYM error invalid_block {
0396  }
0397   | CHARSET_SYM error ';' {
0398  }
0399  ;
0400 
0401 import_list:
0402  /* empty */
0403  | import_list import maybe_sgml {
0404      CSSParser *p = static_cast<CSSParser *>(parser);
0405      if ( $2 && p->styleElement && p->styleElement->isCSSStyleSheet() ) {
0406          p->styleElement->append( $2 );
0407      } else {
0408          delete $2;
0409      }
0410  }
0411  ;
0412 
0413 import:
0414     IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list ';' {
0415 #ifdef CSS_DEBUG
0416         qDebug() << "@import: " << qString($3);
0417 #endif
0418         CSSParser *p = static_cast<CSSParser *>(parser);
0419         if ( $5 && p->styleElement && p->styleElement->isCSSStyleSheet() )
0420             $$ = new CSSImportRuleImpl( p->styleElement, domString($3), $5 );
0421         else
0422             $$ = 0;
0423     }
0424   | IMPORT_SYM error invalid_block {
0425         $$ = 0;
0426     }
0427   | IMPORT_SYM error ';' {
0428         $$ = 0;
0429     }
0430   ;
0431 
0432 namespace_list:
0433     /* empty */ %prec REDUCE
0434   | namespace_list namespace maybe_sgml
0435 ;
0436 
0437 namespace_rule:
0438 NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri {
0439 #ifdef CSS_DEBUG
0440     qDebug() << "@namespace: " << qString($3) << qString($4);
0441 #endif
0442     CSSParser *p = static_cast<CSSParser *>(parser);
0443     $$ = new CSSNamespaceRuleImpl(p->styleElement, domString($3), domString($4));
0444  }
0445     ;
0446 
0447 namespace: 
0448 namespace_rule maybe_space ';' {
0449     CSSParser *p = static_cast<CSSParser *>(parser);
0450     if (p->styleElement && p->styleElement->isCSSStyleSheet())
0451         static_cast<CSSStyleSheetImpl*>(p->styleElement)->appendNamespaceRule
0452                     (static_cast<CSSNamespaceRuleImpl*>($1)); 
0453                             // can't use ->append since it 
0454                             // wouldn't keep track of dirtiness
0455  }
0456 | NAMESPACE_SYM error invalid_block
0457 | NAMESPACE_SYM error ';'
0458     ;
0459 
0460 maybe_ns_prefix:
0461 /* empty */ { $$.string = 0; }
0462 | IDENT S { $$ = $1; }
0463   ;
0464 
0465 rule_list:
0466    /* empty */
0467  | rule_list rule maybe_sgml {
0468      CSSParser *p = static_cast<CSSParser *>(parser);
0469      if ( $2 && p->styleElement && p->styleElement->isCSSStyleSheet() ) {
0470          p->styleElement->append( $2 );
0471      } else {
0472          delete $2;
0473      }
0474  }
0475     ;
0476 
0477 rule:
0478     ruleset
0479   | media
0480   | page
0481   | font_face
0482   | invalid_rule
0483   | invalid_at
0484   | import error { delete $1; $$ = 0; }
0485     ;
0486 
0487 safe_ruleset:
0488     ruleset
0489   | invalid_rule
0490   | invalid_at
0491   | import error { delete $1; $$ = 0; }
0492     ;
0493 
0494 string_or_uri:
0495     STRING
0496   | URI
0497     ;
0498  
0499 media_feature:
0500     IDENT maybe_space {
0501         $$ = $1;
0502     }
0503     ;
0504 
0505 maybe_media_value:
0506     /*empty*/ {
0507         $$ = 0;
0508     }
0509     | ':' maybe_space expr maybe_space {
0510         $$ = $3;
0511     }
0512     ;
0513 
0514 media_query_exp:
0515     '(' maybe_space media_feature maybe_space maybe_media_value ')' maybe_space {
0516         $$ = new khtml::MediaQueryExp(domString($3).lower(), $5);
0517     }
0518     ;
0519 
0520 media_query_exp_list:
0521     media_query_exp {
0522       $$ =  new QList<khtml::MediaQueryExp*>;
0523       $$->append($1);
0524     }
0525     | media_query_exp_list maybe_space MEDIA_AND maybe_space media_query_exp {
0526       $$ = $1;
0527       $$->append($5);
0528     }
0529     ;
0530 
0531 maybe_and_media_query_exp_list:
0532     /*empty*/ {
0533         $$ = new QList<khtml::MediaQueryExp*>;
0534     }
0535     | MEDIA_AND maybe_space media_query_exp_list {
0536         $$ = $3;
0537     }
0538     ;
0539 
0540 maybe_media_restrictor:
0541     /*empty*/ {
0542         $$ = khtml::MediaQuery::None;
0543     }
0544     | MEDIA_ONLY {
0545         $$ = khtml::MediaQuery::Only;
0546     }
0547     | MEDIA_NOT {
0548         $$ = khtml::MediaQuery::Not;
0549     }
0550     ;
0551 
0552 media_query:
0553     media_query_exp_list {
0554         $$ = new khtml::MediaQuery(khtml::MediaQuery::None, "all", $1);
0555     }
0556     | maybe_media_restrictor maybe_space medium maybe_and_media_query_exp_list {
0557         $$ = new khtml::MediaQuery($1, domString($3).lower(), $4);
0558     }
0559     ;
0560 
0561 maybe_media_list:
0562     /* empty */ {
0563         $$ = new MediaListImpl();
0564     }
0565     | media_list
0566 ;
0567 
0568 
0569 media_list:
0570     media_query {
0571         $$ = new MediaListImpl();
0572         $$->appendMediaQuery($1);
0573     }
0574     | media_list ',' maybe_space media_query {
0575         $$ = $1;
0576         if ($$)
0577             $$->appendMediaQuery( $4 );
0578     }
0579     | media_list error {
0580        delete $1;
0581        $$ = 0;
0582     }
0583     ;
0584 
0585 media:
0586     MEDIA_SYM maybe_space media_list '{' maybe_space ruleset_list '}' {
0587         CSSParser *p = static_cast<CSSParser *>(parser);
0588         if ( $3 && $6 &&
0589              p->styleElement && p->styleElement->isCSSStyleSheet() ) {
0590             $$ = new CSSMediaRuleImpl( static_cast<CSSStyleSheetImpl*>(p->styleElement), $3, $6 );
0591         } else {
0592             $$ = 0;
0593             delete $3;
0594             delete $6;
0595         }
0596     }
0597     | MEDIA_SYM maybe_space '{' maybe_space ruleset_list '}' {
0598         CSSParser *p = static_cast<CSSParser *>(parser);
0599         if ($5 && p->styleElement && p->styleElement->isCSSStyleSheet() ) {
0600             $$ = new CSSMediaRuleImpl( static_cast<CSSStyleSheetImpl*>(p->styleElement), 0, $5);
0601         } else {
0602             $$ = 0;
0603             delete $5;
0604         }
0605     }
0606   ;
0607 
0608 ruleset_list:
0609     /* empty */ { $$ = 0; }
0610   | ruleset_list safe_ruleset maybe_space {
0611       $$ = $1;
0612       if ( $2 ) {
0613           if ( !$$ ) $$ = new CSSRuleListImpl();
0614           $$->append( $2 );
0615       }
0616   }
0617     ;
0618 
0619 medium:
0620   IDENT maybe_space {
0621       $$ = $1;
0622   }
0623   ;
0624 
0625 /*
0626 page:
0627     PAGE_SYM maybe_space IDENT? pseudo_page? maybe_space
0628     '{' maybe_space declaration [ ';' maybe_space declaration ]* '}' maybe_space
0629   ;
0630 
0631 pseudo_page
0632   : ':' IDENT
0633   ;
0634 
0635 */
0636 
0637 page:
0638     PAGE_SYM error invalid_block {
0639       $$ = 0;
0640     }
0641   | PAGE_SYM error ';' {
0642       $$ = 0;
0643     }
0644     ;
0645 
0646 font_face:
0647     FONT_FACE_SYM maybe_space declaration_block {
0648       CSSParser *p = static_cast<CSSParser *>(parser);
0649       CSSFontFaceRuleImpl *rule = new CSSFontFaceRuleImpl( p->styleElement );
0650       CSSStyleDeclarationImpl *decl = p->createFontFaceStyleDeclaration( rule );
0651       rule->setDeclaration(decl);
0652       $$ = rule;
0653     }
0654   | FONT_FACE_SYM error invalid_block {
0655       $$ = 0;
0656     }
0657   | FONT_FACE_SYM error ';' {
0658       $$ = 0;
0659     }
0660 ;
0661 
0662 combinator:
0663     '+' maybe_space { $$ = CSSSelector::DirectAdjacent; }
0664   | '~' maybe_space { $$ = CSSSelector::IndirectAdjacent; }
0665   | '>' maybe_space { $$ = CSSSelector::Child; }
0666   ;
0667 
0668 unary_operator:
0669     '-' { $$ = -1; }
0670   | '+' { $$ = 1; }
0671   ;
0672 
0673 ruleset:
0674     selector_list declaration_block {
0675 #ifdef CSS_DEBUG
0676         qDebug() << "got ruleset" << endl << "  selector:";
0677 #endif
0678         CSSParser *p = static_cast<CSSParser *>(parser);
0679         if ( $1  ) {
0680             CSSStyleRuleImpl *rule = new CSSStyleRuleImpl( p->styleElement );
0681             CSSStyleDeclarationImpl *decl = p->createStyleDeclaration( rule );
0682             rule->setSelector( $1 );
0683             rule->setDeclaration(decl);
0684             $$ = rule;
0685         } else {
0686             $$ = 0;
0687             if ($1) qDeleteAll(*$1);
0688             delete $1;
0689             $1 = 0;
0690             p->clearProperties();
0691         }
0692     }
0693   ;
0694 
0695 selector_list:
0696     selector %prec REDUCE {
0697         if ( $1 ) {
0698             $$ = new QList<CSSSelector*>;
0699 #ifdef CSS_DEBUG
0700             qDebug() << "   got simple selector:";
0701             $1->print();
0702 #endif
0703             $$->append( $1 );
0704             khtml::CSSStyleSelector::precomputeAttributeDependencies(static_cast<CSSParser *>(parser)->document(), $1);
0705         } else {
0706             $$ = 0;
0707         }
0708     }
0709     | selector_list ',' maybe_space selector %prec REDUCE {
0710         if ( $1 && $4 ) {
0711             $$ = $1;
0712             $$->append( $4 );
0713             khtml::CSSStyleSelector::precomputeAttributeDependencies(static_cast<CSSParser *>(parser)->document(), $4);
0714 #ifdef CSS_DEBUG
0715             qDebug() << "   got simple selector:";
0716             $4->print();
0717 #endif
0718         } else {
0719             if ($1) qDeleteAll(*$1);
0720             delete $1;
0721             $1=0;
0722 
0723             delete $4;
0724             $$ = 0;
0725         }
0726     }
0727   | selector_list error {
0728         if ($1) qDeleteAll(*$1);
0729         delete $1;
0730         $1 = 0;
0731         $$ = 0;
0732     }
0733    ;
0734 
0735 
0736 selector:
0737     simple_selector {
0738         $$ = $1;
0739     }
0740     | selector S {
0741         $$ = $1;
0742     }
0743     | selector S simple_selector {
0744         if ( !$1 || !$3 ) {
0745             delete $1;
0746             delete $3;
0747             $$ = 0;
0748         } else {
0749             $$ = $3;
0750             CSSSelector *end = $$;
0751             while( end->tagHistory )
0752                 end = end->tagHistory;
0753             end->relation = CSSSelector::Descendant;
0754             end->tagHistory = $1;
0755         }
0756     }
0757     | selector combinator simple_selector {
0758         if ( !$1 || !$3 ) {
0759             delete $1;
0760             delete $3;
0761             $$ = 0;
0762         } else {
0763             $$ = $3;
0764             CSSSelector *end = $3;
0765             while( end->tagHistory )
0766                 end = end->tagHistory;
0767             end->relation = $2;
0768             end->tagHistory = $1;
0769         }
0770     }
0771     | selector error {
0772         delete $1;
0773         $$ = 0;
0774     }
0775     ;
0776 
0777 namespace_selector:
0778     /* empty */ '|' { $$.string = 0; $$.length = 0; }
0779     | '*' '|' { static unsigned short star = '*'; $$.string = &star; $$.length = 1; }
0780     | IDENT '|' { $$ = $1; }
0781 ;
0782 
0783 simple_selector:
0784     element_name {
0785         $$ = new CSSSelector();
0786         $$->tagLocalName = LocalName::fromId(localNamePart($1));
0787         $$->tagNamespace = NamespaceName::fromId(namespacePart($1));
0788     }
0789     | element_name specifier_list {
0790         $$ = $2;
0791         if ( $$ ) {
0792             $$->tagLocalName = LocalName::fromId(localNamePart($1));
0793             $$->tagNamespace = NamespaceName::fromId(namespacePart($1));
0794         }
0795     }
0796     | specifier_list {
0797         $$ = $1;
0798         if ( $$ ) {
0799             $$->tagLocalName = LocalName::fromId(anyLocalName);
0800             $$->tagNamespace = NamespaceName::fromId(static_cast<CSSParser*>(parser)->defaultNamespace());
0801         }
0802     }
0803     | namespace_selector element_name {
0804         $$ = new CSSSelector();
0805         $$->tagLocalName = LocalName::fromId(localNamePart($2));
0806         $$->tagNamespace = NamespaceName::fromId(namespacePart($2));
0807         CSSParser *p = static_cast<CSSParser *>(parser);
0808         if (p->styleElement && p->styleElement->isCSSStyleSheet())
0809             static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->tagNamespace, domString($1));
0810     }
0811     | namespace_selector element_name specifier_list {
0812         $$ = $3;
0813         if ($$) {
0814             $$->tagLocalName = LocalName::fromId(localNamePart($2));
0815             $$->tagNamespace = NamespaceName::fromId(namespacePart($2));
0816             CSSParser *p = static_cast<CSSParser *>(parser);
0817             if (p->styleElement && p->styleElement->isCSSStyleSheet())
0818                 static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->tagNamespace, domString($1));
0819         }
0820     }
0821     | namespace_selector specifier_list {
0822         $$ = $2;
0823         if ($$) {
0824             $$->tagLocalName = LocalName::fromId(anyLocalName);
0825             $$->tagNamespace = NamespaceName::fromId(anyNamespace);
0826             CSSParser *p = static_cast<CSSParser *>(parser);
0827             if (p->styleElement && p->styleElement->isCSSStyleSheet())
0828                 static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->tagNamespace, domString($1));
0829         }
0830     }
0831   ;
0832 
0833 simple_css3_selector:
0834     element_name {
0835         $$ = new CSSSelector();
0836         $$->tagLocalName = LocalName::fromId(localNamePart($1));
0837         $$->tagNamespace = NamespaceName::fromId(namespacePart($1));
0838     }
0839     | specifier {
0840         $$ = $1;
0841         if ( $$ ) {
0842             $$->tagLocalName = LocalName::fromId(anyLocalName);
0843             $$->tagNamespace = NamespaceName::fromId(static_cast<CSSParser*>(parser)->defaultNamespace());
0844         }
0845     }
0846     | namespace_selector element_name {
0847         $$ = new CSSSelector();
0848         $$->tagLocalName = LocalName::fromId(localNamePart($2));
0849         $$->tagNamespace = NamespaceName::fromId(namespacePart($2));
0850         CSSParser *p = static_cast<CSSParser *>(parser);
0851         if (p->styleElement && p->styleElement->isCSSStyleSheet())
0852             static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->tagNamespace, domString($1));
0853     }
0854     | namespace_selector specifier {
0855         $$ = $2;
0856         if ($$) {
0857             $$->tagLocalName = LocalName::fromId(anyLocalName);
0858             $$->tagNamespace = NamespaceName::fromId(anyNamespace);
0859             CSSParser *p = static_cast<CSSParser *>(parser);
0860             if (p->styleElement && p->styleElement->isCSSStyleSheet())
0861                 static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->tagNamespace, domString($1));
0862         }
0863     }
0864   ;
0865 
0866 element_name:
0867     IDENT {
0868       CSSParser *p = static_cast<CSSParser *>(parser);
0869       $$ = makeId(p->defaultNamespace(), p->getLocalNameId(domString($1)));
0870     }
0871     | '*' {
0872         $$ = makeId(static_cast<CSSParser*>(parser)->defaultNamespace(), anyLocalName);
0873     }
0874   ;
0875 
0876 specifier_list:
0877     specifier {
0878         $$ = $1;
0879     }
0880     | specifier_list specifier {
0881         $$ = $1;
0882         if ( $$ ) {
0883             CSSSelector *end = $1;
0884             while( end->tagHistory )
0885                 end = end->tagHistory;
0886             end->relation = CSSSelector::SubSelector;
0887             end->tagHistory = $2;
0888         }
0889     }
0890     | specifier_list error {
0891         delete $1;
0892         $$ = 0;
0893     }
0894 ;
0895 
0896 specifier:
0897     HASH {
0898         CSSParser *p = static_cast<CSSParser *>(parser);
0899 
0900         $$ = new CSSSelector();
0901         $$->match = CSSSelector::Id;
0902         $$->attrLocalName = LocalName::fromId(localNamePart(ATTR_ID));
0903         $$->attrNamespace = NamespaceName::fromId(namespacePart(ATTR_ID));
0904 
0905         bool caseSensitive = p->document()->htmlMode() == DocumentImpl::XHtml || !p->document()->inCompatMode();
0906         if (caseSensitive)
0907             $$->value = domString($1);
0908         else
0909             $$->value = domString($1).lower();
0910     }
0911   | class
0912   | attrib
0913   | pseudo
0914     ;
0915 
0916 class:
0917     '.' IDENT {
0918         CSSParser *p = static_cast<CSSParser *>(parser);
0919 
0920         $$ = new CSSSelector();
0921         $$->match = CSSSelector::Class;
0922         $$->attrLocalName = LocalName::fromId(localNamePart(ATTR_CLASS));
0923         $$->attrNamespace = NamespaceName::fromId(namespacePart(ATTR_CLASS));
0924 
0925         bool caseSensitive = p->document()->htmlMode() == DocumentImpl::XHtml || !p->document()->inCompatMode();
0926         if (caseSensitive)
0927             $$->value = domString($2);
0928         else
0929             $$->value = domString($2).lower();
0930     }
0931   ;
0932 
0933 attrib_id:
0934     IDENT maybe_space {
0935       CSSParser *p = static_cast<CSSParser *>(parser);
0936       $$ = makeId(emptyNamespace, p->getLocalNameId(domString($1)));
0937     }
0938     ;
0939 
0940 attrib:
0941     '[' maybe_space attrib_id ']' {
0942         $$ = new CSSSelector();
0943         $$->attrLocalName = LocalName::fromId(localNamePart($3));
0944         $$->attrNamespace = NamespaceName::fromId(namespacePart($3));
0945         $$->match = CSSSelector::Set;
0946     }
0947     | '[' maybe_space attrib_id match maybe_space ident_or_string maybe_space ']' {
0948         $$ = new CSSSelector();
0949         $$->attrLocalName = LocalName::fromId(localNamePart($3));
0950         $$->attrNamespace = NamespaceName::fromId(namespacePart($3));
0951         $$->match = $4;
0952         $$->value = domString($6);
0953     }
0954     | '[' maybe_space namespace_selector attrib_id ']' {
0955         $$ = new CSSSelector();
0956         $$->attrLocalName = LocalName::fromId(localNamePart($4));
0957         $$->attrNamespace = NamespaceName::fromId(namespacePart($4));
0958         $$->match = CSSSelector::Set;
0959         CSSParser *p = static_cast<CSSParser *>(parser);
0960         if (p->styleElement && p->styleElement->isCSSStyleSheet())
0961             static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->attrNamespace, domString($3));
0962     }
0963     | '[' maybe_space namespace_selector attrib_id match maybe_space ident_or_string maybe_space ']' {
0964         $$ = new CSSSelector();
0965         $$->attrLocalName = LocalName::fromId(localNamePart($4));
0966         $$->attrNamespace = NamespaceName::fromId(namespacePart($4));
0967         $$->match = (CSSSelector::Match)$5;
0968         $$->value = domString($7);
0969         CSSParser *p = static_cast<CSSParser *>(parser);
0970         if (p->styleElement && p->styleElement->isCSSStyleSheet())
0971             static_cast<CSSStyleSheetImpl*>(p->styleElement)->determineNamespace($$->attrNamespace, domString($3));
0972    }
0973   ;
0974 
0975 match:
0976     '=' {
0977         $$ = CSSSelector::Exact;
0978     }
0979     | INCLUDES {
0980         $$ = CSSSelector::List;
0981     }
0982     | DASHMATCH {
0983         $$ = CSSSelector::Hyphen;
0984     }
0985     | BEGINSWITH {
0986         $$ = CSSSelector::Begin;
0987     }
0988     | ENDSWITH {
0989         $$ = CSSSelector::End;
0990     }
0991     | CONTAINS {
0992         $$ = CSSSelector::Contain;
0993     }
0994     ;
0995 
0996 ident_or_string:
0997     IDENT
0998   | STRING
0999     ;
1000 
1001 pseudo:
1002     ':' IDENT {
1003         $$ = new CSSSelector();
1004         $$->match = CSSSelector::PseudoClass;
1005         $$->value = domString($2);
1006     }
1007     |
1008     ':' ':' IDENT {
1009         $$ = new CSSSelector();
1010         $$->match = CSSSelector::PseudoElement;
1011         $$->value = domString($3);
1012     }
1013     // used by :nth-*
1014     | ':' FUNCTION maybe_space NTH maybe_space ')' {
1015         $$ = new CSSSelector();
1016         $$->match = CSSSelector::PseudoClass;
1017         $$->string_arg = domString($4);
1018         $$->value = domString($2);
1019     }
1020     // used by :nth-*
1021     | ':' FUNCTION maybe_space maybe_plus INTEGER maybe_space ')' {
1022         $$ = new CSSSelector();
1023         $$->match = CSSSelector::PseudoClass;
1024         $$->string_arg = QString::number($5);
1025         $$->value = domString($2);
1026     }
1027     // used by :nth-* and :lang
1028     | ':' FUNCTION maybe_space IDENT maybe_space ')' {
1029         $$ = new CSSSelector();
1030         $$->match = CSSSelector::PseudoClass;
1031         $$->string_arg = domString($4);
1032         $$->value = domString($2);
1033     }
1034     // used by :contains and :lang
1035     | ':' FUNCTION maybe_space STRING maybe_space ')' {
1036         $$ = new CSSSelector();
1037         $$->match = CSSSelector::PseudoClass;
1038         $$->string_arg = domString($4);
1039         $$->value = domString($2);
1040     }
1041     // used only by :not
1042     | ':' NOTFUNCTION maybe_space simple_css3_selector maybe_space ')' {
1043         $$ = new CSSSelector();
1044         $$->match = CSSSelector::PseudoClass;
1045         $$->simpleSelector = $4;
1046         $$->value = domString($2);
1047     }
1048   ;
1049 
1050 declaration_block:
1051     '{' maybe_space declaration '}' {
1052         $$ = $3;
1053     }
1054     | '{' maybe_space error '}' {
1055         $$ = false;
1056     }
1057     | '{' maybe_space declaration_list '}' {
1058         $$ = $3;
1059     }
1060     | '{' maybe_space declaration_list declaration '}' {
1061         $$ = $3;
1062         if ( $4 )
1063             $$ = $4;
1064     }
1065     | '{' maybe_space declaration_list error '}' {
1066         $$ = $3;
1067     }
1068     ;
1069 
1070 declaration_list:
1071     declaration ';' maybe_space {
1072         $$ = $1;
1073     }
1074     |
1075     error ';' maybe_space {
1076         $$ = false;
1077     }
1078     | declaration_list declaration ';' maybe_space {
1079         $$ = $1;
1080         if ( $2 )
1081             $$ = $2;
1082     }
1083     | declaration_list error ';' maybe_space {
1084         $$ = $1;
1085     }
1086     ;
1087 
1088 declaration:
1089     property ':' maybe_space expr prio {
1090         $$ = false;
1091         CSSParser *p = static_cast<CSSParser *>(parser);
1092         if ( $1 && $4 ) {
1093             p->valueList = $4;
1094 #ifdef CSS_DEBUG
1095             qDebug() << "   got property: " << $1 <<
1096                 ($5?" important":"");
1097 #endif
1098                 bool ok = p->parseValue( $1, $5 );
1099                 if ( ok )
1100                     $$ = ok;
1101 #ifdef CSS_DEBUG
1102                 else
1103                     qDebug() << "     couldn't parse value!";
1104 #endif
1105         } else {
1106             delete $4;
1107         }
1108         delete p->valueList;
1109         p->valueList = 0;
1110     }
1111     | error invalid_block {
1112         $$ = false;
1113     }
1114   ;
1115 
1116 property:
1117     IDENT maybe_space {
1118         QString str = qString($1);
1119         $$ = getPropertyID(str.toLower().toLatin1(), str.length());
1120     }
1121   ;
1122 
1123 prio:
1124     IMPORTANT_SYM maybe_space { $$ = true; }
1125     | /* empty */ { $$ = false; }
1126   ;
1127 
1128 expr:
1129     term {
1130         $$ = new ValueList;
1131         $$->addValue( $1 );
1132     }
1133     | expr operator term {
1134         $$ = $1;
1135         if ( $$ ) {
1136             if ( $2 ) {
1137                 Value v;
1138                 v.id = 0;
1139                 v.unit = Value::Operator;
1140                 v.iValue = $2;
1141                 $$->addValue( v );
1142             }
1143             $$->addValue( $3 );
1144         }
1145     }
1146   ;
1147 
1148 operator:
1149     '/' maybe_space {
1150         $$ = '/';
1151     }
1152   | ',' maybe_space {
1153         $$ = ',';
1154     }
1155   | /* empty */ {
1156         $$ = 0;
1157   }
1158   ;
1159 
1160 term:
1161   unary_term { $$ = $1; }
1162    | unary_operator unary_term { $$ = $2; $$.fValue *= $1; }
1163   /* DIMEN is an unary_term, but since we store the string we must not modify fValue */
1164   | DIMEN maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION; }
1165   | STRING maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; }
1166   | IDENT maybe_space {
1167       QString str = qString( $1 );
1168       $$.id = getValueID( str.toLower().toLatin1(), str.length() );
1169       $$.unit = CSSPrimitiveValue::CSS_IDENT;
1170       $$.string = $1;
1171   }
1172   | URI maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; }
1173   | UNICODERANGE maybe_space { $$.id = 0; $$.iValue = 0; $$.unit = CSSPrimitiveValue::CSS_UNKNOWN;/* ### */ }
1174   | hexcolor { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_RGBCOLOR; }
1175 /* ### according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
1176   | function {
1177       $$ = $1;
1178   }
1179   ;
1180 
1181 unary_term:
1182   INTEGER maybe_space { $$.id = 0; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1183   | FLOAT maybe_space { $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
1184   | PERCENTAGE maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; }
1185   | PXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; }
1186   | CMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; }
1187   | MMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; }
1188   | INS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; }
1189   | PTS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; }
1190   | PCS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; }
1191   | DEGS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; }
1192   | RADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; }
1193   | GRADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; }
1194   | MSECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; }
1195   | SECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; }
1196   | HERZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; }
1197   | KHERZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; }
1198   | EMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; }
1199   | QEMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = Value::Q_EMS; }
1200   | EXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; }
1201   | CHS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CHS; }
1202   | REMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_REMS; }
1203   | DPI maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPI; }
1204   | DPCM maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DPCM; }
1205     ;
1206 
1207 
1208 function:
1209   FUNCTION maybe_space expr ')' maybe_space {
1210       Function *f = new Function;
1211       f->name = $1;
1212       f->args = $3;
1213       $$.id = 0;
1214       $$.unit = Value::Function;
1215       $$.function = f;
1216   }
1217   | FUNCTION maybe_space error {
1218       Function *f = new Function;
1219       f->name = $1;
1220       f->args = 0;
1221       $$.id = 0;
1222       $$.unit = Value::Function;
1223       $$.function = f;
1224   }
1225 
1226   ;
1227 /*
1228  * There is a constraint on the color that it must
1229  * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
1230  * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
1231  */
1232 hexcolor:
1233   HEXCOLOR maybe_space { $$ = $1; }
1234   ;
1235 
1236 
1237 /* error handling rules */
1238 
1239 invalid_at:
1240     '@' error invalid_block {
1241         $$ = 0;
1242 #ifdef CSS_DEBUG
1243         qDebug() << "skipped invalid @-rule";
1244 #endif
1245     }
1246   | '@' error ';' {
1247         $$ = 0;
1248 #ifdef CSS_DEBUG
1249         qDebug() << "skipped invalid @-rule";
1250 #endif
1251     }
1252     ;
1253 
1254 invalid_rule:
1255     error invalid_block {
1256         $$ = 0;
1257 #ifdef CSS_DEBUG
1258         qDebug() << "skipped invalid rule";
1259 #endif
1260     }
1261 /*
1262   Seems like the two rules below are trying too much and violating
1263   https://www.hixie.ch/tests/evil/mixed/csserrorhandling.html
1264 
1265   | error ';' {
1266         $$ = 0;
1267 #ifdef CSS_DEBUG
1268         qDebug() << "skipped invalid rule";
1269 #endif
1270     }
1271   | error '}' {
1272         $$ = 0;
1273 #ifdef CSS_DEBUG
1274         qDebug() << "skipped invalid rule";
1275 #endif
1276     }
1277 */
1278     ;
1279 
1280 invalid_block:
1281     '{' error invalid_block_list error '}'
1282   | '{' error '}'
1283     ;
1284 
1285 invalid_block_list:
1286     invalid_block
1287   | invalid_block_list error invalid_block
1288 ;
1289 
1290 %%
1291