summaryrefslogtreecommitdiffstats
path: root/WebCore/css/CSSGrammar.y
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/css/CSSGrammar.y')
-rw-r--r--WebCore/css/CSSGrammar.y1493
1 files changed, 1493 insertions, 0 deletions
diff --git a/WebCore/css/CSSGrammar.y b/WebCore/css/CSSGrammar.y
new file mode 100644
index 0000000..f6b0c17
--- /dev/null
+++ b/WebCore/css/CSSGrammar.y
@@ -0,0 +1,1493 @@
+%{
+
+/*
+ * Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+
+#include "CSSMediaRule.h"
+#include "CSSParser.h"
+#include "CSSPropertyNames.h"
+#include "CSSRuleList.h"
+#include "CSSSelector.h"
+#include "CSSNthSelector.h"
+#include "CSSStyleSheet.h"
+#include "Document.h"
+#include "HTMLNames.h"
+#include "MediaList.h"
+#include "WebKitCSSKeyframeRule.h"
+#include "WebKitCSSKeyframesRule.h"
+#include <stdlib.h>
+#include <string.h>
+
+using namespace WebCore;
+using namespace HTMLNames;
+
+#define YYENABLE_NLS 0
+#define YYLTYPE_IS_TRIVIAL 1
+#define YYMAXDEPTH 10000
+#define YYDEBUG 0
+
+// FIXME: Replace with %parse-param { CSSParser* parser } once we can depend on bison 2.x
+#define YYPARSE_PARAM parser
+#define YYLEX_PARAM parser
+
+%}
+
+%pure_parser
+
+%union {
+ bool boolean;
+ char character;
+ int integer;
+ double number;
+ CSSParserString string;
+
+ CSSRule* rule;
+ CSSRuleList* ruleList;
+ CSSSelector* selector;
+ CSSSelector::Relation relation;
+ MediaList* mediaList;
+ MediaQuery* mediaQuery;
+ MediaQuery::Restrictor mediaQueryRestrictor;
+ MediaQueryExp* mediaQueryExp;
+ CSSParserValue value;
+ CSSParserValueList* valueList;
+ Vector<MediaQueryExp*>* mediaQueryExpList;
+ WebKitCSSKeyframeRule* keyframeRule;
+ WebKitCSSKeyframesRule* keyframesRule;
+ float val;
+}
+
+%{
+
+static inline int cssyyerror(const char*)
+{
+ return 1;
+}
+
+static int cssyylex(YYSTYPE* yylval, void* parser)
+{
+ return static_cast<CSSParser*>(parser)->lex(yylval);
+}
+
+%}
+
+%expect 48
+
+%left UNIMPORTANT_TOK
+
+%token WHITESPACE SGML_CD
+%token TOKEN_EOF 0
+
+%token INCLUDES
+%token DASHMATCH
+%token BEGINSWITH
+%token ENDSWITH
+%token CONTAINS
+
+%token <string> STRING
+%right <string> IDENT
+%token <string> NTH
+
+%nonassoc <string> HEX
+%nonassoc <string> IDSEL
+%nonassoc ':'
+%nonassoc '.'
+%nonassoc '['
+%nonassoc <string> '*'
+%nonassoc error
+%left '|'
+
+%token IMPORT_SYM
+%token PAGE_SYM
+%token MEDIA_SYM
+%token FONT_FACE_SYM
+%token CHARSET_SYM
+%token NAMESPACE_SYM
+%token WEBKIT_RULE_SYM
+%token WEBKIT_DECLS_SYM
+%token WEBKIT_KEYFRAME_RULE_SYM
+%token WEBKIT_KEYFRAMES_SYM
+%token WEBKIT_VALUE_SYM
+%token WEBKIT_MEDIAQUERY_SYM
+%token WEBKIT_SELECTOR_SYM
+%token WEBKIT_VARIABLES_SYM
+%token WEBKIT_DEFINE_SYM
+%token VARIABLES_FOR
+%token WEBKIT_VARIABLES_DECLS_SYM
+%token ATKEYWORD
+
+%token IMPORTANT_SYM
+%token MEDIA_ONLY
+%token MEDIA_NOT
+%token MEDIA_AND
+
+%token <number> QEMS
+%token <number> EMS
+%token <number> EXS
+%token <number> PXS
+%token <number> CMS
+%token <number> MMS
+%token <number> INS
+%token <number> PTS
+%token <number> PCS
+%token <number> DEGS
+%token <number> RADS
+%token <number> GRADS
+%token <number> MSECS
+%token <number> SECS
+%token <number> HERZ
+%token <number> KHERZ
+%token <string> DIMEN
+%token <number> PERCENTAGE
+%token <number> FLOATTOKEN
+%token <number> INTEGER
+
+%token <string> URI
+%token <string> FUNCTION
+%token <string> NOTFUNCTION
+
+%token <string> UNICODERANGE
+
+%token <string> VARCALL
+
+%type <relation> combinator
+
+%type <rule> charset
+%type <rule> ruleset
+%type <rule> valid_rule_or_import
+%type <rule> media
+%type <rule> import
+%type <rule> page
+%type <rule> font_face
+%type <rule> keyframes
+%type <rule> invalid_rule
+%type <rule> save_block
+%type <rule> invalid_at
+%type <rule> invalid_at_list
+%type <rule> invalid_import
+%type <rule> invalid_media
+%type <rule> rule
+%type <rule> valid_rule
+%type <ruleList> block_rule_list
+%type <rule> block_rule
+%type <rule> block_valid_rule
+%type <rule> variables_rule
+%type <mediaList> variables_media_list
+
+%type <string> maybe_ns_prefix
+
+%type <string> namespace_selector
+
+%type <string> string_or_uri
+%type <string> ident_or_string
+%type <string> medium
+%type <string> hexcolor
+
+%type <string> media_feature
+%type <mediaList> media_list
+%type <mediaList> maybe_media_list
+%type <mediaQuery> media_query
+%type <mediaQueryRestrictor> maybe_media_restrictor
+%type <valueList> maybe_media_value
+%type <mediaQueryExp> media_query_exp
+%type <mediaQueryExpList> media_query_exp_list
+%type <mediaQueryExpList> maybe_and_media_query_exp_list
+
+%type <string> keyframe_name
+%type <keyframeRule> keyframe_rule
+%type <keyframesRule> keyframes_rule
+%type <valueList> key_list
+%type <value> key
+
+%type <integer> property
+
+%type <selector> specifier
+%type <selector> specifier_list
+%type <selector> simple_selector
+%type <selector> selector
+%type <selector> selector_list
+%type <selector> selector_with_trailing_whitespace
+%type <selector> class
+%type <selector> attrib
+%type <selector> pseudo
+
+%type <boolean> declaration_list
+%type <boolean> decl_list
+%type <boolean> declaration
+
+%type <boolean> prio
+
+%type <integer> match
+%type <integer> unary_operator
+%type <character> operator
+
+%type <valueList> expr
+%type <value> term
+%type <value> unary_term
+%type <value> function
+
+%type <string> element_name
+%type <string> attr_name
+
+%type <string> variable_name
+%type <boolean> variables_declaration_list
+%type <boolean> variables_decl_list
+%type <boolean> variables_declaration
+%type <value> variable_reference
+
+%%
+
+stylesheet:
+ maybe_charset maybe_sgml import_list variables_list namespace_list rule_list
+ | webkit_rule maybe_space
+ | webkit_decls maybe_space
+ | webkit_value maybe_space
+ | webkit_mediaquery maybe_space
+ | webkit_selector maybe_space
+ | webkit_variables_decls maybe_space
+ | webkit_keyframe_rule maybe_space
+ ;
+
+valid_rule_or_import:
+ valid_rule
+ | import
+ ;
+
+webkit_rule:
+ WEBKIT_RULE_SYM '{' maybe_space valid_rule_or_import maybe_space '}' {
+ static_cast<CSSParser*>(parser)->m_rule = $4;
+ }
+;
+
+webkit_keyframe_rule:
+ WEBKIT_KEYFRAME_RULE_SYM '{' maybe_space keyframe_rule maybe_space '}' {
+ static_cast<CSSParser*>(parser)->m_keyframe = $4;
+ }
+;
+
+webkit_decls:
+ WEBKIT_DECLS_SYM '{' maybe_space declaration_list '}' {
+ /* can be empty */
+ }
+;
+
+webkit_variables_decls:
+ WEBKIT_VARIABLES_DECLS_SYM '{' maybe_space variables_declaration_list '}' {
+ /* can be empty */
+ }
+;
+
+webkit_value:
+ WEBKIT_VALUE_SYM '{' maybe_space expr '}' {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if ($4) {
+ p->m_valueList = p->sinkFloatingValueList($4);
+ int oldParsedProperties = p->m_numParsedProperties;
+ if (!p->parseValue(p->m_id, p->m_important))
+ p->rollbackLastProperties(p->m_numParsedProperties - oldParsedProperties);
+ delete p->m_valueList;
+ p->m_valueList = 0;
+ }
+ }
+;
+
+webkit_mediaquery:
+ WEBKIT_MEDIAQUERY_SYM WHITESPACE maybe_space media_query '}' {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ p->m_mediaQuery = p->sinkFloatingMediaQuery($4);
+ }
+;
+
+webkit_selector:
+ WEBKIT_SELECTOR_SYM '{' maybe_space selector_list '}' {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ p->m_floatingSelector = p->sinkFloatingSelector($4);
+ }
+;
+
+maybe_space:
+ /* empty */ %prec UNIMPORTANT_TOK
+ | maybe_space WHITESPACE
+ ;
+
+maybe_sgml:
+ /* empty */
+ | maybe_sgml SGML_CD
+ | maybe_sgml WHITESPACE
+ ;
+
+maybe_charset:
+ /* empty */
+ | charset {
+ }
+ ;
+
+closing_brace:
+ '}'
+ | %prec maybe_sgml TOKEN_EOF
+ ;
+
+charset:
+ CHARSET_SYM maybe_space STRING maybe_space ';' {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = static_cast<CSSParser*>(parser)->createCharsetRule($3);
+ if ($$ && p->m_styleSheet)
+ p->m_styleSheet->append($$);
+ }
+ | CHARSET_SYM error invalid_block {
+ }
+ | CHARSET_SYM error ';' {
+ }
+;
+
+import_list:
+ /* empty */
+ | import_list import maybe_sgml {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if ($2 && p->m_styleSheet)
+ p->m_styleSheet->append($2);
+ }
+ | invalid_at_list {
+ }
+ ;
+
+variables_list:
+/* empty */
+| variables_list variables_rule maybe_sgml {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if ($2 && p->m_styleSheet)
+ p->m_styleSheet->append($2);
+}
+;
+
+namespace_list:
+/* empty */
+| namespace_list namespace maybe_sgml
+;
+
+rule_list:
+ /* empty */
+ | rule_list rule maybe_sgml {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if ($2 && p->m_styleSheet)
+ p->m_styleSheet->append($2);
+ }
+ ;
+
+valid_rule:
+ ruleset
+ | media
+ | page
+ | font_face
+ | keyframes
+ ;
+
+rule:
+ valid_rule
+ | invalid_rule
+ | invalid_at
+ | invalid_import
+ ;
+
+block_rule_list:
+ /* empty */ { $$ = 0; }
+ | block_rule_list block_rule maybe_sgml {
+ $$ = $1;
+ if ($2) {
+ if (!$$)
+ $$ = static_cast<CSSParser*>(parser)->createRuleList();
+ $$->append($2);
+ }
+ }
+ ;
+
+block_valid_rule:
+ ruleset
+ | page
+ | font_face
+ | keyframes
+ ;
+
+block_rule:
+ block_valid_rule
+ | invalid_rule
+ | invalid_at
+ | invalid_import
+ | invalid_media
+ ;
+
+
+import:
+ IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list ';' {
+ $$ = static_cast<CSSParser*>(parser)->createImportRule($3, $5);
+ }
+ | IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list invalid_block {
+ $$ = 0;
+ }
+ | IMPORT_SYM error ';' {
+ $$ = 0;
+ }
+ | IMPORT_SYM error invalid_block {
+ $$ = 0;
+ }
+ ;
+
+variables_rule:
+ WEBKIT_VARIABLES_SYM maybe_space maybe_media_list '{' maybe_space variables_declaration_list '}' {
+ $$ = static_cast<CSSParser*>(parser)->createVariablesRule($3, true);
+ }
+ |
+ WEBKIT_DEFINE_SYM maybe_space variables_media_list '{' maybe_space variables_declaration_list '}' {
+ $$ = static_cast<CSSParser*>(parser)->createVariablesRule($3, false);
+ }
+ ;
+
+variables_media_list:
+ /* empty */ {
+ $$ = static_cast<CSSParser*>(parser)->createMediaList();
+ }
+ |
+ VARIABLES_FOR WHITESPACE media_list {
+ $$ = $3;
+ }
+ ;
+
+variables_declaration_list:
+ variables_declaration {
+ $$ = $1;
+ }
+ | variables_decl_list variables_declaration {
+ $$ = $1;
+ if ($2)
+ $$ = $2;
+ }
+ | variables_decl_list {
+ $$ = $1;
+ }
+ | error invalid_block_list error {
+ $$ = false;
+ }
+ | error {
+ $$ = false;
+ }
+ | variables_decl_list error {
+ $$ = $1;
+ }
+ ;
+
+variables_decl_list:
+ variables_declaration ';' maybe_space {
+ $$ = $1;
+ }
+ | variables_declaration invalid_block_list ';' maybe_space {
+ $$ = false;
+ }
+ | error ';' maybe_space {
+ $$ = false;
+ }
+ | error invalid_block_list error ';' maybe_space {
+ $$ = false;
+ }
+ | variables_decl_list variables_declaration ';' maybe_space {
+ $$ = $1;
+ if ($2)
+ $$ = $2;
+ }
+ | variables_decl_list error ';' maybe_space {
+ $$ = $1;
+ }
+ | variables_decl_list error invalid_block_list error ';' maybe_space {
+ $$ = $1;
+ }
+ ;
+
+variables_declaration:
+ variable_name ':' maybe_space expr {
+ $$ = static_cast<CSSParser*>(parser)->addVariable($1, $4);
+ }
+ |
+ variable_name maybe_space '{' maybe_space declaration_list '}' maybe_space {
+ $$ = static_cast<CSSParser*>(parser)->addVariableDeclarationBlock($1);
+ }
+ |
+ variable_name error {
+ $$ = false;
+ }
+ |
+ variable_name ':' maybe_space error expr {
+ $$ = false;
+ }
+ |
+ variable_name ':' maybe_space {
+ /* @variables { varname: } Just reduce away this variable with no value. */
+ $$ = false;
+ }
+ |
+ variable_name ':' maybe_space error {
+ /* if we come across rules with invalid values like this case: @variables { varname: *; }, just discard the property/value pair */
+ $$ = false;
+ }
+ ;
+
+variable_name:
+ IDENT maybe_space {
+ $$ = $1;
+ }
+ ;
+
+namespace:
+NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space ';' {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if (p->m_styleSheet)
+ p->m_styleSheet->addNamespace(p, $3, $4);
+}
+| NAMESPACE_SYM error invalid_block
+| NAMESPACE_SYM error ';'
+;
+
+maybe_ns_prefix:
+/* empty */ { $$.characters = 0; }
+| IDENT WHITESPACE { $$ = $1; }
+;
+
+string_or_uri:
+STRING
+| URI
+;
+
+media_feature:
+ IDENT maybe_space {
+ $$ = $1;
+ }
+ ;
+
+maybe_media_value:
+ /*empty*/ {
+ $$ = 0;
+ }
+ | ':' maybe_space expr maybe_space {
+ $$ = $3;
+ }
+ ;
+
+media_query_exp:
+ '(' maybe_space media_feature maybe_space maybe_media_value ')' maybe_space {
+ $3.lower();
+ $$ = static_cast<CSSParser*>(parser)->createFloatingMediaQueryExp($3, $5);
+ }
+ ;
+
+media_query_exp_list:
+ media_query_exp {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingMediaQueryExpList();
+ $$->append(p->sinkFloatingMediaQueryExp($1));
+ }
+ | media_query_exp_list maybe_space MEDIA_AND maybe_space media_query_exp {
+ $$ = $1;
+ $$->append(static_cast<CSSParser*>(parser)->sinkFloatingMediaQueryExp($5));
+ }
+ ;
+
+maybe_and_media_query_exp_list:
+ /*empty*/ {
+ $$ = static_cast<CSSParser*>(parser)->createFloatingMediaQueryExpList();
+ }
+ | MEDIA_AND maybe_space media_query_exp_list {
+ $$ = $3;
+ }
+ ;
+
+maybe_media_restrictor:
+ /*empty*/ {
+ $$ = MediaQuery::None;
+ }
+ | MEDIA_ONLY {
+ $$ = MediaQuery::Only;
+ }
+ | MEDIA_NOT {
+ $$ = MediaQuery::Not;
+ }
+ ;
+
+media_query:
+ media_query_exp_list {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingMediaQuery(p->sinkFloatingMediaQueryExpList($1));
+ }
+ |
+ maybe_media_restrictor maybe_space medium maybe_and_media_query_exp_list {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $3.lower();
+ $$ = p->createFloatingMediaQuery($1, $3, p->sinkFloatingMediaQueryExpList($4));
+ }
+ ;
+
+maybe_media_list:
+ /* empty */ {
+ $$ = static_cast<CSSParser*>(parser)->createMediaList();
+ }
+ | media_list
+ ;
+
+media_list:
+ media_query {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createMediaList();
+ $$->appendMediaQuery(p->sinkFloatingMediaQuery($1));
+ }
+ | media_list ',' maybe_space media_query {
+ $$ = $1;
+ if ($$)
+ $$->appendMediaQuery(static_cast<CSSParser*>(parser)->sinkFloatingMediaQuery($4));
+ }
+ | media_list error {
+ $$ = 0;
+ }
+ ;
+
+media:
+ MEDIA_SYM maybe_space media_list '{' maybe_space block_rule_list save_block {
+ $$ = static_cast<CSSParser*>(parser)->createMediaRule($3, $6);
+ }
+ | MEDIA_SYM maybe_space '{' maybe_space block_rule_list save_block {
+ $$ = static_cast<CSSParser*>(parser)->createMediaRule(0, $5);
+ }
+ ;
+
+medium:
+ IDENT maybe_space {
+ $$ = $1;
+ }
+ ;
+
+keyframes:
+ WEBKIT_KEYFRAMES_SYM maybe_space keyframe_name maybe_space '{' maybe_space keyframes_rule '}' {
+ $$ = $7;
+ $7->setNameInternal($3);
+ }
+ ;
+
+keyframe_name:
+ IDENT
+ | STRING
+ ;
+
+keyframes_rule:
+ /* empty */ { $$ = static_cast<CSSParser*>(parser)->createKeyframesRule(); }
+ | keyframes_rule keyframe_rule maybe_space {
+ $$ = $1;
+ if ($2)
+ $$->append($2);
+ }
+ ;
+
+keyframe_rule:
+ key_list maybe_space '{' maybe_space declaration_list '}' {
+ $$ = static_cast<CSSParser*>(parser)->createKeyframeRule($1);
+ }
+ ;
+
+key_list:
+ key {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingValueList();
+ $$->addValue(p->sinkFloatingValue($1));
+ }
+ | key_list maybe_space ',' maybe_space key {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = $1;
+ if ($$)
+ $$->addValue(p->sinkFloatingValue($5));
+ }
+ ;
+
+key:
+ PERCENTAGE { $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
+ | IDENT {
+ $$.id = 0; $$.isInt = false; $$.unit = CSSPrimitiveValue::CSS_NUMBER;
+ CSSParserString& str = $1;
+ if (equalIgnoringCase(static_cast<const String&>(str), "from"))
+ $$.fValue = 0;
+ else if (equalIgnoringCase(static_cast<const String&>(str), "to"))
+ $$.fValue = 100;
+ else
+ YYERROR;
+ }
+ ;
+
+/*
+page:
+ PAGE_SYM maybe_space IDENT? pseudo_page? maybe_space
+ '{' maybe_space declaration [ ';' maybe_space declaration ]* '}' maybe_space
+ ;
+
+pseudo_page
+ : ':' IDENT
+ ;
+*/
+
+page:
+ PAGE_SYM error invalid_block {
+ $$ = 0;
+ }
+ | PAGE_SYM error ';' {
+ $$ = 0;
+ }
+ ;
+
+font_face:
+ FONT_FACE_SYM maybe_space
+ '{' maybe_space declaration_list '}' maybe_space {
+ $$ = static_cast<CSSParser*>(parser)->createFontFaceRule();
+ }
+ | FONT_FACE_SYM error invalid_block {
+ $$ = 0;
+ }
+ | FONT_FACE_SYM error ';' {
+ $$ = 0;
+ }
+;
+
+combinator:
+ '+' maybe_space { $$ = CSSSelector::DirectAdjacent; }
+ | '~' maybe_space { $$ = CSSSelector::IndirectAdjacent; }
+ | '>' maybe_space { $$ = CSSSelector::Child; }
+ ;
+
+unary_operator:
+ '-' { $$ = -1; }
+ | '+' { $$ = 1; }
+ ;
+
+ruleset:
+ selector_list '{' maybe_space declaration_list closing_brace {
+ $$ = static_cast<CSSParser*>(parser)->createStyleRule($1);
+ }
+ ;
+
+selector_list:
+ selector %prec UNIMPORTANT_TOK {
+ $$ = $1;
+ }
+ | selector_list ',' maybe_space selector %prec UNIMPORTANT_TOK {
+ if ($1 && $4) {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = $1;
+ $$->append(p->sinkFloatingSelector($4));
+ } else
+ $$ = 0;
+ }
+ | selector_list error {
+ $$ = 0;
+ }
+ ;
+
+selector_with_trailing_whitespace:
+ selector WHITESPACE {
+ $$ = $1;
+ }
+ ;
+
+selector:
+ simple_selector {
+ $$ = $1;
+ }
+ | selector_with_trailing_whitespace
+ {
+ $$ = $1;
+ }
+ | selector_with_trailing_whitespace simple_selector
+ {
+ $$ = $2;
+ if (!$1)
+ $$ = 0;
+ else if ($$) {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ CSSSelector* end = $$;
+ while (end->m_tagHistory)
+ end = end->m_tagHistory;
+ end->m_relation = CSSSelector::Descendant;
+ end->m_tagHistory = p->sinkFloatingSelector($1);
+ if (Document* doc = p->document())
+ doc->setUsesDescendantRules(true);
+ }
+ }
+ | selector combinator simple_selector {
+ $$ = $3;
+ if (!$1)
+ $$ = 0;
+ else if ($$) {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ CSSSelector* end = $$;
+ while (end->m_tagHistory)
+ end = end->m_tagHistory;
+ end->m_relation = $2;
+ end->m_tagHistory = p->sinkFloatingSelector($1);
+ if ($2 == CSSSelector::Child) {
+ if (Document* doc = p->document())
+ doc->setUsesDescendantRules(true);
+ } else if ($2 == CSSSelector::DirectAdjacent || $2 == CSSSelector::IndirectAdjacent) {
+ if (Document* doc = p->document())
+ doc->setUsesSiblingRules(true);
+ }
+ }
+ }
+ | selector error {
+ $$ = 0;
+ }
+ ;
+
+namespace_selector:
+ /* empty */ '|' { $$.characters = 0; $$.length = 0; }
+ | '*' '|' { static UChar star = '*'; $$.characters = &star; $$.length = 1; }
+ | IDENT '|' { $$ = $1; }
+;
+
+simple_selector:
+ element_name {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingSelector();
+ $$->m_tag = QualifiedName(nullAtom, $1, p->m_defaultNamespace);
+ }
+ | element_name specifier_list {
+ $$ = $2;
+ if ($$) {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$->m_tag = QualifiedName(nullAtom, $1, p->m_defaultNamespace);
+ }
+ }
+ | specifier_list {
+ $$ = $1;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if ($$ && p->m_defaultNamespace != starAtom)
+ $$->m_tag = QualifiedName(nullAtom, starAtom, p->m_defaultNamespace);
+ }
+ | namespace_selector element_name {
+ AtomicString namespacePrefix = $1;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingSelector();
+ if (p->m_styleSheet)
+ $$->m_tag = QualifiedName(namespacePrefix, $2,
+ p->m_styleSheet->determineNamespace(namespacePrefix));
+ else // FIXME: Shouldn't this case be an error?
+ $$->m_tag = QualifiedName(nullAtom, $2, p->m_defaultNamespace);
+ }
+ | namespace_selector element_name specifier_list {
+ $$ = $3;
+ if ($$) {
+ AtomicString namespacePrefix = $1;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if (p->m_styleSheet)
+ $$->m_tag = QualifiedName(namespacePrefix, $2,
+ p->m_styleSheet->determineNamespace(namespacePrefix));
+ else // FIXME: Shouldn't this case be an error?
+ $$->m_tag = QualifiedName(nullAtom, $2, p->m_defaultNamespace);
+ }
+ }
+ | namespace_selector specifier_list {
+ $$ = $2;
+ if ($$) {
+ AtomicString namespacePrefix = $1;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if (p->m_styleSheet)
+ $$->m_tag = QualifiedName(namespacePrefix, starAtom,
+ p->m_styleSheet->determineNamespace(namespacePrefix));
+ }
+ }
+ ;
+
+element_name:
+ IDENT {
+ CSSParserString& str = $1;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ Document* doc = p->document();
+ if (doc && doc->isHTMLDocument())
+ str.lower();
+ $$ = str;
+ }
+ | '*' {
+ static UChar star = '*';
+ $$.characters = &star;
+ $$.length = 1;
+ }
+ ;
+
+specifier_list:
+ specifier {
+ $$ = $1;
+ }
+ | specifier_list specifier {
+ if (!$2)
+ $$ = 0;
+ else if ($1) {
+ $$ = $1;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ CSSSelector* end = $1;
+ while (end->m_tagHistory)
+ end = end->m_tagHistory;
+ end->m_relation = CSSSelector::SubSelector;
+ end->m_tagHistory = p->sinkFloatingSelector($2);
+ }
+ }
+ | specifier_list error {
+ $$ = 0;
+ }
+;
+
+specifier:
+ IDSEL {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingSelector();
+ $$->m_match = CSSSelector::Id;
+ if (!p->m_strict)
+ $1.lower();
+ $$->m_attr = idAttr;
+ $$->m_value = $1;
+ }
+ | HEX {
+ if ($1.characters[0] >= '0' && $1.characters[0] <= '9') {
+ $$ = 0;
+ } else {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingSelector();
+ $$->m_match = CSSSelector::Id;
+ if (!p->m_strict)
+ $1.lower();
+ $$->m_attr = idAttr;
+ $$->m_value = $1;
+ }
+ }
+ | class
+ | attrib
+ | pseudo
+ ;
+
+class:
+ '.' IDENT {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingSelector();
+ $$->m_match = CSSSelector::Class;
+ if (!p->m_strict)
+ $2.lower();
+ $$->m_attr = classAttr;
+ $$->m_value = $2;
+ }
+ ;
+
+attr_name:
+ IDENT maybe_space {
+ CSSParserString& str = $1;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ Document* doc = p->document();
+ if (doc && doc->isHTMLDocument())
+ str.lower();
+ $$ = str;
+ }
+ ;
+
+attrib:
+ '[' maybe_space attr_name ']' {
+ $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
+ $$->m_attr = QualifiedName(nullAtom, $3, nullAtom);
+ $$->m_match = CSSSelector::Set;
+ }
+ | '[' maybe_space attr_name match maybe_space ident_or_string maybe_space ']' {
+ $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
+ $$->m_attr = QualifiedName(nullAtom, $3, nullAtom);
+ $$->m_match = (CSSSelector::Match)$4;
+ $$->m_value = $6;
+ }
+ | '[' maybe_space namespace_selector attr_name ']' {
+ AtomicString namespacePrefix = $3;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingSelector();
+ $$->m_attr = QualifiedName(namespacePrefix, $4,
+ p->m_styleSheet->determineNamespace(namespacePrefix));
+ $$->m_match = CSSSelector::Set;
+ }
+ | '[' maybe_space namespace_selector attr_name match maybe_space ident_or_string maybe_space ']' {
+ AtomicString namespacePrefix = $3;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingSelector();
+ $$->m_attr = QualifiedName(namespacePrefix, $4,
+ p->m_styleSheet->determineNamespace(namespacePrefix));
+ $$->m_match = (CSSSelector::Match)$5;
+ $$->m_value = $7;
+ }
+ ;
+
+match:
+ '=' {
+ $$ = CSSSelector::Exact;
+ }
+ | INCLUDES {
+ $$ = CSSSelector::List;
+ }
+ | DASHMATCH {
+ $$ = CSSSelector::Hyphen;
+ }
+ | BEGINSWITH {
+ $$ = CSSSelector::Begin;
+ }
+ | ENDSWITH {
+ $$ = CSSSelector::End;
+ }
+ | CONTAINS {
+ $$ = CSSSelector::Contain;
+ }
+ ;
+
+ident_or_string:
+ IDENT
+ | STRING
+ ;
+
+pseudo:
+ ':' IDENT {
+ $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
+ $$->m_match = CSSSelector::PseudoClass;
+ $2.lower();
+ $$->m_value = $2;
+ CSSSelector::PseudoType type = $$->pseudoType();
+ if (type == CSSSelector::PseudoUnknown)
+ $$ = 0;
+ else if (type == CSSSelector::PseudoEmpty ||
+ type == CSSSelector::PseudoFirstChild ||
+ type == CSSSelector::PseudoFirstOfType ||
+ type == CSSSelector::PseudoLastChild ||
+ type == CSSSelector::PseudoLastOfType ||
+ type == CSSSelector::PseudoOnlyChild ||
+ type == CSSSelector::PseudoOnlyOfType) {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ Document* doc = p->document();
+ if (doc)
+ doc->setUsesSiblingRules(true);
+ } else if (type == CSSSelector::PseudoFirstLine) {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if (Document* doc = p->document())
+ doc->setUsesFirstLineRules(true);
+ }
+ }
+ | ':' ':' IDENT {
+ $$ = static_cast<CSSParser*>(parser)->createFloatingSelector();
+ $$->m_match = CSSSelector::PseudoElement;
+ $3.lower();
+ $$->m_value = $3;
+ CSSSelector::PseudoType type = $$->pseudoType();
+ if (type == CSSSelector::PseudoUnknown)
+ $$ = 0;
+ else if (type == CSSSelector::PseudoFirstLine) {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if (Document* doc = p->document())
+ doc->setUsesFirstLineRules(true);
+ }
+ }
+ // used by :nth-*(ax+b)
+ | ':' FUNCTION NTH ')' {
+ CSSParser *p = static_cast<CSSParser*>(parser);
+ $$ = static_cast<CSSSelector*>(p->createFloatingNthSelector());
+ $$->m_match = CSSSelector::PseudoClass;
+ $$->m_argument = $3;
+ $$->m_value = $2;
+ CSSSelector::PseudoType type = $$->pseudoType();
+ if (type == CSSSelector::PseudoUnknown)
+ $$ = 0;
+ else if (type == CSSSelector::PseudoNthChild ||
+ type == CSSSelector::PseudoNthOfType ||
+ type == CSSSelector::PseudoNthLastChild ||
+ type == CSSSelector::PseudoNthLastOfType) {
+ if (p->document())
+ p->document()->setUsesSiblingRules(true);
+ }
+ }
+ // used by :nth-*
+ | ':' FUNCTION INTEGER ')' {
+ CSSParser *p = static_cast<CSSParser*>(parser);
+ $$ = static_cast<CSSSelector*>(p->createFloatingNthSelector());
+ $$->m_match = CSSSelector::PseudoClass;
+ $$->m_argument = String::number($3);
+ $$->m_value = $2;
+ CSSSelector::PseudoType type = $$->pseudoType();
+ if (type == CSSSelector::PseudoUnknown)
+ $$ = 0;
+ else if (type == CSSSelector::PseudoNthChild ||
+ type == CSSSelector::PseudoNthOfType ||
+ type == CSSSelector::PseudoNthLastChild ||
+ type == CSSSelector::PseudoNthLastOfType) {
+ if (p->document())
+ p->document()->setUsesSiblingRules(true);
+ }
+ }
+ // used by :nth-*(odd/even) and :lang
+ | ':' FUNCTION IDENT ')' {
+ CSSParser *p = static_cast<CSSParser*>(parser);
+ $$ = static_cast<CSSSelector*>(p->createFloatingNthSelector());
+ $$->m_match = CSSSelector::PseudoClass;
+ $$->m_argument = $3;
+ $2.lower();
+ $$->m_value = $2;
+ CSSSelector::PseudoType type = $$->pseudoType();
+ if (type == CSSSelector::PseudoUnknown)
+ $$ = 0;
+ else if (type == CSSSelector::PseudoNthChild ||
+ type == CSSSelector::PseudoNthOfType ||
+ type == CSSSelector::PseudoNthLastChild ||
+ type == CSSSelector::PseudoNthLastOfType) {
+ if (p->document())
+ p->document()->setUsesSiblingRules(true);
+ }
+ }
+ // used by :not
+ | ':' NOTFUNCTION maybe_space simple_selector maybe_space ')' {
+ if (!$4)
+ $$ = 0;
+ else {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingSelector();
+ $$->m_match = CSSSelector::PseudoClass;
+ $$->m_simpleSelector = p->sinkFloatingSelector($4);
+ $2.lower();
+ $$->m_value = $2;
+ }
+ }
+ ;
+
+declaration_list:
+ declaration {
+ $$ = $1;
+ }
+ | decl_list declaration {
+ $$ = $1;
+ if ( $2 )
+ $$ = $2;
+ }
+ | decl_list {
+ $$ = $1;
+ }
+ | error invalid_block_list error {
+ $$ = false;
+ }
+ | error {
+ $$ = false;
+ }
+ | decl_list error {
+ $$ = $1;
+ }
+ | decl_list invalid_block_list {
+ $$ = $1;
+ }
+ ;
+
+decl_list:
+ declaration ';' maybe_space {
+ $$ = $1;
+ }
+ | declaration invalid_block_list ';' maybe_space {
+ $$ = false;
+ }
+ | error ';' maybe_space {
+ $$ = false;
+ }
+ | error invalid_block_list error ';' maybe_space {
+ $$ = false;
+ }
+ | decl_list declaration ';' maybe_space {
+ $$ = $1;
+ if ($2)
+ $$ = $2;
+ }
+ | decl_list error ';' maybe_space {
+ $$ = $1;
+ }
+ | decl_list error invalid_block_list error ';' maybe_space {
+ $$ = $1;
+ }
+ ;
+
+declaration:
+ property ':' maybe_space expr prio {
+ $$ = false;
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ if ($1 && $4) {
+ p->m_valueList = p->sinkFloatingValueList($4);
+ int oldParsedProperties = p->m_numParsedProperties;
+ $$ = p->parseValue($1, $5);
+ if (!$$)
+ p->rollbackLastProperties(p->m_numParsedProperties - oldParsedProperties);
+ delete p->m_valueList;
+ p->m_valueList = 0;
+ }
+ }
+ |
+ variable_reference maybe_space {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ p->m_valueList = new CSSParserValueList;
+ p->m_valueList->addValue(p->sinkFloatingValue($1));
+ int oldParsedProperties = p->m_numParsedProperties;
+ $$ = p->parseValue(CSSPropertyWebkitVariableDeclarationBlock, false);
+ if (!$$)
+ p->rollbackLastProperties(p->m_numParsedProperties - oldParsedProperties);
+ delete p->m_valueList;
+ p->m_valueList = 0;
+ }
+ |
+ property error {
+ $$ = false;
+ }
+ |
+ property ':' maybe_space error expr prio {
+ /* The default movable type template has letter-spacing: .none; Handle this by looking for
+ error tokens at the start of an expr, recover the expr and then treat as an error, cleaning
+ up and deleting the shifted expr. */
+ $$ = false;
+ }
+ |
+ property ':' maybe_space expr prio error {
+ /* When we encounter something like p {color: red !important fail;} we should drop the declaration */
+ $$ = false;
+ }
+ |
+ IMPORTANT_SYM maybe_space {
+ /* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */
+ $$ = false;
+ }
+ |
+ property ':' maybe_space {
+ /* div { font-family: } Just reduce away this property with no value. */
+ $$ = false;
+ }
+ |
+ property ':' maybe_space error {
+ /* if we come across rules with invalid values like this case: p { weight: *; }, just discard the rule */
+ $$ = false;
+ }
+ |
+ property invalid_block {
+ /* if we come across: div { color{;color:maroon} }, ignore everything within curly brackets */
+ $$ = false;
+ }
+ ;
+
+property:
+ IDENT maybe_space {
+ $$ = cssPropertyID($1);
+ }
+ ;
+
+prio:
+ IMPORTANT_SYM maybe_space { $$ = true; }
+ | /* empty */ { $$ = false; }
+ ;
+
+expr:
+ term {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = p->createFloatingValueList();
+ $$->addValue(p->sinkFloatingValue($1));
+ }
+ | expr operator term {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ $$ = $1;
+ if ($$) {
+ if ($2) {
+ CSSParserValue v;
+ v.id = 0;
+ v.unit = CSSParserValue::Operator;
+ v.iValue = $2;
+ $$->addValue(v);
+ }
+ $$->addValue(p->sinkFloatingValue($3));
+ }
+ }
+ | expr error {
+ $$ = 0;
+ }
+ ;
+
+operator:
+ '/' maybe_space {
+ $$ = '/';
+ }
+ | ',' maybe_space {
+ $$ = ',';
+ }
+ | /* empty */ {
+ $$ = 0;
+ }
+ ;
+
+term:
+ unary_term { $$ = $1; }
+ | unary_operator unary_term { $$ = $2; $$.fValue *= $1; }
+ | STRING maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_STRING; }
+ | IDENT maybe_space {
+ $$.id = cssValueKeywordID($1);
+ $$.unit = CSSPrimitiveValue::CSS_IDENT;
+ $$.string = $1;
+ }
+ /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */
+ | DIMEN maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_DIMENSION }
+ | unary_operator DIMEN maybe_space { $$.id = 0; $$.string = $2; $$.unit = CSSPrimitiveValue::CSS_DIMENSION }
+ | URI maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_URI; }
+ | UNICODERANGE maybe_space { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_UNICODE_RANGE }
+ | hexcolor { $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; }
+ | '#' maybe_space { $$.id = 0; $$.string = CSSParserString(); $$.unit = CSSPrimitiveValue::CSS_PARSER_HEXCOLOR; } /* Handle error case: "color: #;" */
+ /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
+ | function {
+ $$ = $1;
+ }
+ | variable_reference maybe_space {
+ $$ = $1;
+ }
+ | '%' maybe_space { $$.id = 0; $$.fValue = 0; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; } /* Handle width: %; ANDROID: Fix an uninitialized Value object causing the device to crash */
+ ;
+
+unary_term:
+ INTEGER maybe_space { $$.id = 0; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
+ | FLOATTOKEN maybe_space { $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_NUMBER; }
+ | PERCENTAGE maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PERCENTAGE; }
+ | PXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PX; }
+ | CMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_CM; }
+ | MMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MM; }
+ | INS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_IN; }
+ | PTS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PT; }
+ | PCS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_PC; }
+ | DEGS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_DEG; }
+ | RADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_RAD; }
+ | GRADS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_GRAD; }
+ | MSECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_MS; }
+ | SECS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_S; }
+ | HERZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_HZ; }
+ | KHERZ maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_KHZ; }
+ | EMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EMS; }
+ | QEMS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSParserValue::Q_EMS; }
+ | EXS maybe_space { $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue::CSS_EXS; }
+ ;
+
+variable_reference:
+ VARCALL {
+ $$.id = 0;
+ $$.string = $1;
+ $$.unit = CSSPrimitiveValue::CSS_PARSER_VARIABLE_FUNCTION_SYNTAX;
+ }
+ ;
+
+function:
+ FUNCTION maybe_space expr ')' maybe_space {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ CSSParserFunction* f = p->createFloatingFunction();
+ f->name = $1;
+ f->args = p->sinkFloatingValueList($3);
+ $$.id = 0;
+ $$.unit = CSSParserValue::Function;
+ $$.function = f;
+ } |
+ FUNCTION maybe_space error {
+ CSSParser* p = static_cast<CSSParser*>(parser);
+ CSSParserFunction* f = p->createFloatingFunction();
+ f->name = $1;
+ f->args = 0;
+ $$.id = 0;
+ $$.unit = CSSParserValue::Function;
+ $$.function = f;
+ }
+ ;
+/*
+ * There is a constraint on the color that it must
+ * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
+ * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
+ */
+hexcolor:
+ HEX maybe_space { $$ = $1; }
+ | IDSEL maybe_space { $$ = $1; }
+ ;
+
+
+/* error handling rules */
+
+save_block:
+ closing_brace {
+ $$ = 0;
+ }
+ | error closing_brace {
+ $$ = 0;
+ }
+ ;
+
+invalid_at:
+ ATKEYWORD error invalid_block {
+ $$ = 0;
+ }
+ | ATKEYWORD error ';' {
+ $$ = 0;
+ }
+ ;
+
+invalid_at_list:
+ invalid_at maybe_sgml
+ | invalid_at_list invalid_at maybe_sgml
+ ;
+
+invalid_import:
+ import {
+ $$ = 0;
+ }
+ ;
+
+invalid_media:
+ media {
+ $$ = 0;
+ }
+ ;
+
+invalid_rule:
+ error invalid_block {
+ $$ = 0;
+ }
+
+/*
+ Seems like the two rules below are trying too much and violating
+ http://www.hixie.ch/tests/evil/mixed/csserrorhandling.html
+
+ | error ';' {
+ $$ = 0;
+ }
+ | error '}' {
+ $$ = 0;
+ }
+*/
+ ;
+
+invalid_block:
+ '{' error invalid_block_list error closing_brace
+ | '{' error closing_brace
+ ;
+
+invalid_block_list:
+ invalid_block
+ | invalid_block_list error invalid_block
+;
+
+%%