You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
775 lines
17 KiB
775 lines
17 KiB
/*****************************************************************************
|
|
* CSSGrammar.y: bison production rules for simplified css parsing
|
|
*****************************************************************************
|
|
* Copyright © 2017 VideoLabs, VideoLAN and VLC Authors
|
|
*
|
|
* Adapted from webkit's CSSGrammar.y:
|
|
*
|
|
* Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org)
|
|
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
|
|
* Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
|
|
* Copyright (C) 2008 Eric Seidel <eric@webkit.org>
|
|
* Copyright (C) 2012 Intel Corporation. All rights reserved.
|
|
*
|
|
* 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
|
|
*
|
|
*/
|
|
%define api.pure full
|
|
%define api.prefix {css}
|
|
|
|
%param { yyscan_t scanner }
|
|
%parse-param { vlc_css_parser_t *css_parser }
|
|
|
|
|
|
%{
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
#include <vlc_common.h>
|
|
#include "css_parser.h"
|
|
|
|
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
|
#define YY_TYPEDEF_YY_SCANNER_T
|
|
typedef void* yyscan_t;
|
|
#endif
|
|
%}
|
|
|
|
%union {
|
|
bool boolean;
|
|
char character;
|
|
int integer;
|
|
char *string;
|
|
enum vlc_css_relation_e relation;
|
|
|
|
vlc_css_term_t term;
|
|
vlc_css_expr_t *expr;
|
|
vlc_css_rule_t *rule;
|
|
vlc_css_declaration_t *declaration;
|
|
vlc_css_declaration_t *declarationList;
|
|
vlc_css_selector_t *selector;
|
|
vlc_css_selector_t *selectorList;
|
|
}
|
|
|
|
%{
|
|
/* See bison pure calling */
|
|
#define YY_DECL int yylex(union YYSTYPE *, yyscan_t)
|
|
YY_DECL;
|
|
|
|
static void yyerror(yyscan_t scanner, vlc_css_parser_t *p, const char *msg)
|
|
{
|
|
VLC_UNUSED(scanner);VLC_UNUSED(p);VLC_UNUSED(msg);
|
|
}
|
|
|
|
%}
|
|
|
|
%expect 10
|
|
|
|
%nonassoc LOWEST_PREC
|
|
|
|
%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
|
|
|
|
%nonassoc <string> IDSEL
|
|
%nonassoc <string> HASH
|
|
%nonassoc ':'
|
|
%nonassoc '.'
|
|
%nonassoc '['
|
|
%nonassoc <character> '*'
|
|
%nonassoc error
|
|
%left '|'
|
|
|
|
%token FONT_FACE_SYM
|
|
%token CHARSET_SYM
|
|
|
|
%token IMPORTANT_SYM
|
|
|
|
%token CDO
|
|
%token CDC
|
|
%token <term> LENGTH
|
|
%token <term> ANGLE
|
|
%token <term> TIME
|
|
%token <term> FREQ
|
|
%token <term> DIMEN
|
|
%token <term> PERCENTAGE
|
|
%token <term> NUMBER
|
|
|
|
%destructor { vlc_css_term_Clean($$); } <term>
|
|
|
|
%token <string> URI
|
|
%token <string> FUNCTION
|
|
%token <string> UNICODERANGE
|
|
|
|
%type <relation> combinator
|
|
|
|
%type <rule> charset
|
|
%type <rule> ignored_charset
|
|
%type <rule> ruleset
|
|
%type <rule> font_face
|
|
%type <rule> invalid_rule
|
|
%type <rule> rule
|
|
%type <rule> valid_rule
|
|
%destructor { vlc_css_rules_Delete($$); } <rule>
|
|
|
|
%type <string> ident_or_string
|
|
%type <string> property
|
|
|
|
%type <selector> specifier
|
|
%type <selector> specifier_list
|
|
%type <selector> simple_selector
|
|
%type <selector> selector
|
|
%type <selectorList> selector_list
|
|
%type <selector> selector_with_trailing_whitespace
|
|
%type <selector> class
|
|
%type <selector> attrib
|
|
%type <selector> pseudo
|
|
%destructor { vlc_css_selectors_Delete($$); } <selector> <selectorList>
|
|
|
|
%type <declarationList> declaration_list
|
|
%type <declarationList> decl_list
|
|
%type <declaration> declaration
|
|
%destructor { vlc_css_declarations_Delete($$); } <declaration> <declarationList>
|
|
|
|
%type <boolean> prio
|
|
|
|
%type <integer> match
|
|
%type <integer> unary_operator
|
|
%type <integer> maybe_unary_operator
|
|
%type <character> operator
|
|
|
|
%type <expr> expr
|
|
%type <term> term
|
|
%type <term> unary_term
|
|
%type <term> function
|
|
%destructor { vlc_css_expression_Delete($$); } <expr>
|
|
|
|
%type <string> element_name
|
|
%type <string> attr_name
|
|
|
|
%destructor { free($$); } <string>
|
|
|
|
%%
|
|
|
|
stylesheet:
|
|
maybe_space maybe_charset maybe_sgml rule_list
|
|
;
|
|
|
|
maybe_space:
|
|
/* empty */ %prec UNIMPORTANT_TOK
|
|
| maybe_space WHITESPACE
|
|
;
|
|
|
|
maybe_sgml:
|
|
/* empty */
|
|
| maybe_sgml SGML_CD
|
|
| maybe_sgml WHITESPACE
|
|
;
|
|
|
|
maybe_charset:
|
|
/* empty */
|
|
| charset {
|
|
vlc_css_rules_Delete($1);
|
|
}
|
|
;
|
|
|
|
closing_brace:
|
|
'}'
|
|
| %prec LOWEST_PREC TOKEN_EOF
|
|
;
|
|
|
|
charset:
|
|
CHARSET_SYM maybe_space STRING maybe_space ';' {
|
|
free( $3 );
|
|
$$ = 0;
|
|
}
|
|
| CHARSET_SYM error invalid_block {
|
|
$$ = 0;
|
|
}
|
|
| CHARSET_SYM error ';' {
|
|
$$ = 0;
|
|
}
|
|
;
|
|
|
|
ignored_charset:
|
|
CHARSET_SYM maybe_space STRING maybe_space ';' {
|
|
// Ignore any @charset rule not at the beginning of the style sheet.
|
|
free( $3 );
|
|
$$ = 0;
|
|
}
|
|
| CHARSET_SYM maybe_space ';' {
|
|
$$ = 0;
|
|
}
|
|
;
|
|
|
|
rule_list:
|
|
/* empty */
|
|
| rule_list rule maybe_sgml {
|
|
if( $2 )
|
|
vlc_css_parser_AddRule( css_parser, $2 );
|
|
}
|
|
;
|
|
|
|
valid_rule:
|
|
ruleset
|
|
| font_face
|
|
;
|
|
|
|
rule:
|
|
valid_rule {
|
|
$$ = $1;
|
|
if($$)
|
|
$$->b_valid = true;
|
|
}
|
|
| ignored_charset
|
|
| invalid_rule
|
|
;
|
|
|
|
font_face:
|
|
FONT_FACE_SYM maybe_space
|
|
'{' maybe_space declaration_list closing_brace {
|
|
vlc_css_declarations_Delete( $5 );
|
|
$$ = NULL;
|
|
}
|
|
| FONT_FACE_SYM error invalid_block {
|
|
$$ = NULL;
|
|
}
|
|
| FONT_FACE_SYM error ';' {
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
combinator:
|
|
'+' maybe_space { $$ = RELATION_DIRECTADJACENT; }
|
|
| '~' maybe_space { $$ = RELATION_INDIRECTADJACENT; }
|
|
| '>' maybe_space { $$ = RELATION_CHILD; }
|
|
;
|
|
|
|
maybe_unary_operator:
|
|
unary_operator { $$ = $1; }
|
|
| { $$ = 1; }
|
|
;
|
|
|
|
unary_operator:
|
|
'-' { $$ = -1; }
|
|
| '+' { $$ = 1; }
|
|
;
|
|
|
|
ruleset:
|
|
selector_list '{' maybe_space declaration_list closing_brace {
|
|
$$ = vlc_css_rule_New();
|
|
if($$)
|
|
{
|
|
$$->p_selectors = $1;
|
|
$$->p_declarations = $4;
|
|
}
|
|
}
|
|
;
|
|
|
|
selector_list:
|
|
selector %prec UNIMPORTANT_TOK {
|
|
if ($1) {
|
|
$$ = $1;
|
|
}
|
|
}
|
|
| selector_list ',' maybe_space selector %prec UNIMPORTANT_TOK {
|
|
if ($1 && $4 )
|
|
{
|
|
$$ = $1;
|
|
vlc_css_selector_Append( $$, $4 );
|
|
}
|
|
else
|
|
{
|
|
vlc_css_selectors_Delete( $1 );
|
|
vlc_css_selectors_Delete( $4 );
|
|
$$ = NULL;
|
|
}
|
|
}
|
|
| selector_list error {
|
|
vlc_css_selectors_Delete( $1 );
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
selector_with_trailing_whitespace:
|
|
selector WHITESPACE {
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
selector:
|
|
simple_selector {
|
|
$$ = $1;
|
|
}
|
|
| selector_with_trailing_whitespace
|
|
{
|
|
$$ = $1;
|
|
}
|
|
| selector_with_trailing_whitespace simple_selector
|
|
{
|
|
$$ = $1;
|
|
if ($$)
|
|
{
|
|
vlc_css_selector_AddSpecifier( $$, $2 );
|
|
$2->combinator = RELATION_DESCENDENT;
|
|
}
|
|
else $$ = $2;
|
|
}
|
|
| selector combinator simple_selector {
|
|
$$ = $1;
|
|
if ($$)
|
|
{
|
|
vlc_css_selector_AddSpecifier( $$, $3 );
|
|
$3->combinator = $2;
|
|
}
|
|
else $$ = $3;
|
|
}
|
|
| selector error {
|
|
vlc_css_selectors_Delete( $1 );
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
simple_selector:
|
|
element_name {
|
|
$$ = vlc_css_selector_New( SELECTOR_SIMPLE, $1 );
|
|
free( $1 );
|
|
}
|
|
| element_name specifier_list {
|
|
$$ = vlc_css_selector_New( SELECTOR_SIMPLE, $1 );
|
|
if( $$ && $2 )
|
|
{
|
|
vlc_css_selector_AddSpecifier( $$, $2 );
|
|
}
|
|
else
|
|
{
|
|
vlc_css_selectors_Delete( $2 );
|
|
}
|
|
free( $1 );
|
|
}
|
|
| specifier_list {
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
element_name:
|
|
IDENT
|
|
| '*' { $$ = strdup("*"); }
|
|
;
|
|
|
|
specifier_list:
|
|
specifier {
|
|
$$ = $1;
|
|
}
|
|
| specifier_list specifier {
|
|
if( $1 )
|
|
{
|
|
$$ = $1;
|
|
while( $1->specifiers.p_first )
|
|
$1 = $1->specifiers.p_first;
|
|
vlc_css_selector_AddSpecifier( $1, $2 );
|
|
}
|
|
else $$ = $2;
|
|
}
|
|
| specifier_list error {
|
|
vlc_css_selectors_Delete( $1 );
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
specifier:
|
|
IDSEL {
|
|
$$ = vlc_css_selector_New( SPECIFIER_ID, $1 );
|
|
free( $1 );
|
|
}
|
|
/* Case when #fffaaa like token is lexed as HEX instead of IDSEL */
|
|
| HASH {
|
|
if ($1[0] >= '0' && $1[0] <= '9') {
|
|
$$ = NULL;
|
|
} else {
|
|
$$ = vlc_css_selector_New( SPECIFIER_ID, $1 );
|
|
}
|
|
free( $1 );
|
|
}
|
|
| class
|
|
| attrib
|
|
| pseudo
|
|
;
|
|
|
|
class:
|
|
'.' IDENT {
|
|
$$ = vlc_css_selector_New( SPECIFIER_CLASS, $2 );
|
|
free( $2 );
|
|
}
|
|
;
|
|
|
|
attr_name:
|
|
IDENT maybe_space {
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
attrib:
|
|
'[' maybe_space attr_name ']' {
|
|
$$ = vlc_css_selector_New( SPECIFIER_ATTRIB, $3 );
|
|
free( $3 );
|
|
}
|
|
| '[' maybe_space attr_name match maybe_space ident_or_string maybe_space ']' {
|
|
$$ = vlc_css_selector_New( SPECIFIER_ATTRIB, $3 );
|
|
if( $$ )
|
|
{
|
|
$$->match = $4;
|
|
$$->p_matchsel = vlc_css_selector_New( SPECIFIER_ID, $6 );
|
|
}
|
|
free( $3 );
|
|
free( $6 );
|
|
}
|
|
;
|
|
|
|
match:
|
|
'=' {
|
|
$$ = MATCH_EQUALS;
|
|
}
|
|
| INCLUDES {
|
|
$$ = MATCH_INCLUDES;
|
|
}
|
|
| DASHMATCH {
|
|
$$ = MATCH_DASHMATCH;
|
|
}
|
|
| BEGINSWITH {
|
|
$$ = MATCH_BEGINSWITH;
|
|
}
|
|
| ENDSWITH {
|
|
$$ = MATCH_ENDSWITH;
|
|
}
|
|
| CONTAINS {
|
|
$$ = MATCH_CONTAINS;
|
|
}
|
|
;
|
|
|
|
ident_or_string:
|
|
IDENT
|
|
| STRING
|
|
;
|
|
|
|
pseudo:
|
|
':' IDENT {
|
|
$$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
|
|
free( $2 );
|
|
}
|
|
| ':' ':' IDENT {
|
|
$$ = vlc_css_selector_New( SELECTOR_PSEUDOELEMENT, $3 );
|
|
free( $3 );
|
|
}
|
|
// used by :nth-*
|
|
| ':' FUNCTION maybe_space maybe_unary_operator NUMBER maybe_space ')' {
|
|
if(*$2 != 0)
|
|
$2[strlen($2) - 1] = 0;
|
|
$$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
|
|
$5.val *= $4;
|
|
free( $2 );
|
|
vlc_css_term_Clean( $5 );
|
|
}
|
|
// required for WEBVTT weirdos cue::(::past)
|
|
| ':' ':' FUNCTION maybe_space selector maybe_space ')' {
|
|
if(*$3 != 0)
|
|
$3[strlen($3) - 1] = 0;
|
|
$$ = vlc_css_selector_New( SELECTOR_PSEUDOELEMENT, $3 );
|
|
free( $3 );
|
|
if( $$ && $5 )
|
|
{
|
|
vlc_css_selector_AddSpecifier( $$, $5 );
|
|
$5->combinator = RELATION_SELF;
|
|
}
|
|
else
|
|
vlc_css_selectors_Delete( $5 );
|
|
}
|
|
// used by :nth-*(odd/even) and :lang
|
|
| ':' FUNCTION maybe_space IDENT maybe_space ')' {
|
|
if(*$2 != 0)
|
|
$2[strlen($2) - 1] = 0;
|
|
$$ = vlc_css_selector_New( SELECTOR_PSEUDOCLASS, $2 );
|
|
free( $2 );
|
|
free( $4 );
|
|
}
|
|
;
|
|
|
|
declaration_list:
|
|
declaration {
|
|
$$ = $1;
|
|
}
|
|
| decl_list declaration {
|
|
$$ = $1;
|
|
if( $$ )
|
|
vlc_css_declarations_Append( $$, $2 );
|
|
}
|
|
| decl_list {
|
|
$$ = $1;
|
|
}
|
|
| error invalid_block_list error {
|
|
$$ = NULL;
|
|
}
|
|
| error {
|
|
$$ = NULL;
|
|
}
|
|
| decl_list error {
|
|
$$ = $1;
|
|
}
|
|
| decl_list invalid_block_list {
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
decl_list:
|
|
declaration ';' maybe_space {
|
|
$$ = $1;
|
|
}
|
|
| declaration invalid_block_list maybe_space {
|
|
vlc_css_declarations_Delete( $1 );
|
|
$$ = NULL;
|
|
}
|
|
| declaration invalid_block_list ';' maybe_space {
|
|
vlc_css_declarations_Delete( $1 );
|
|
$$ = NULL;
|
|
}
|
|
| error ';' maybe_space {
|
|
$$ = NULL;
|
|
}
|
|
| error invalid_block_list error ';' maybe_space {
|
|
$$ = NULL;
|
|
}
|
|
| decl_list declaration ';' maybe_space {
|
|
if( $1 )
|
|
{
|
|
$$ = $1;
|
|
vlc_css_declarations_Append( $$, $2 );
|
|
}
|
|
else $$ = $2;
|
|
}
|
|
| decl_list error ';' maybe_space {
|
|
$$ = $1;
|
|
}
|
|
| decl_list error invalid_block_list error ';' maybe_space {
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
declaration:
|
|
property ':' maybe_space expr prio {
|
|
$$ = vlc_css_declaration_New( $1 );
|
|
if( $$ )
|
|
$$->expr = $4;
|
|
else
|
|
vlc_css_expression_Delete( $4 );
|
|
free( $1 );
|
|
}
|
|
|
|
|
property error {
|
|
free( $1 );
|
|
$$ = NULL;
|
|
}
|
|
|
|
|
property ':' maybe_space error expr prio {
|
|
free( $1 );
|
|
vlc_css_expression_Delete( $5 );
|
|
/* 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. */
|
|
$$ = NULL;
|
|
}
|
|
|
|
|
property ':' maybe_space expr prio error {
|
|
free( $1 );
|
|
vlc_css_expression_Delete( $4 );
|
|
/* When we encounter something like p {color: red !important fail;} we should drop the declaration */
|
|
$$ = NULL;
|
|
}
|
|
|
|
|
IMPORTANT_SYM maybe_space {
|
|
/* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */
|
|
$$ = NULL;
|
|
}
|
|
|
|
|
property ':' maybe_space {
|
|
free( $1 );
|
|
/* div { font-family: } Just reduce away this property with no value. */
|
|
$$ = NULL;
|
|
}
|
|
|
|
|
property ':' maybe_space error {
|
|
free( $1 );
|
|
/* if we come across rules with invalid values like this case: p { weight: *; }, just discard the rule */
|
|
$$ = NULL;
|
|
}
|
|
|
|
|
property invalid_block {
|
|
/* if we come across: div { color{;color:maroon} }, ignore everything within curly brackets */
|
|
free( $1 );
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
property:
|
|
IDENT maybe_space {
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
prio:
|
|
IMPORTANT_SYM maybe_space { $$ = true; }
|
|
| /* empty */ { $$ = false; }
|
|
;
|
|
|
|
expr:
|
|
term {
|
|
$$ = vlc_css_expression_New( $1 );
|
|
if( !$$ )
|
|
vlc_css_term_Clean( $1 );
|
|
}
|
|
| expr operator term {
|
|
$$ = $1;
|
|
if( !$1 || !vlc_css_expression_AddTerm($1, $2, $3) )
|
|
vlc_css_term_Clean( $3 );
|
|
}
|
|
| expr invalid_block_list {
|
|
vlc_css_expression_Delete( $1 );
|
|
$$ = NULL;
|
|
}
|
|
| expr invalid_block_list error {
|
|
vlc_css_expression_Delete( $1 );
|
|
$$ = NULL;
|
|
}
|
|
| expr error {
|
|
vlc_css_expression_Delete( $1 );
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
operator:
|
|
'/' maybe_space {
|
|
$$ = '/';
|
|
}
|
|
| ',' maybe_space {
|
|
$$ = ',';
|
|
}
|
|
| /* empty */ {
|
|
$$ = 0;
|
|
}
|
|
;
|
|
|
|
term:
|
|
unary_term { $$ = $1; }
|
|
| unary_operator unary_term {
|
|
$$ = $2;
|
|
$$.val *= $1;
|
|
}
|
|
| STRING maybe_space { $$.type = TYPE_STRING; $$.psz = $1; }
|
|
| IDENT maybe_space { $$.type = TYPE_IDENTIFIER; $$.psz = $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 { $$ = $1; }
|
|
| unary_operator DIMEN maybe_space { $$ = $2; }
|
|
| URI maybe_space { $$.type = TYPE_URI; $$.psz = $1; }
|
|
| UNICODERANGE maybe_space { $$.type = TYPE_UNICODERANGE; $$.psz = $1; }
|
|
| IDSEL maybe_space { $$.type = TYPE_HEXCOLOR; $$.psz = $1; }
|
|
| HASH maybe_space { $$.type = TYPE_HEXCOLOR; $$.psz = $1; }
|
|
| '#' maybe_space { $$.type = TYPE_HEXCOLOR; $$.psz = NULL; } /* 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;
|
|
}
|
|
| '%' maybe_space { /* Handle width: %; */
|
|
$$.type = TYPE_PERCENT; $$.val = 0;
|
|
}
|
|
;
|
|
|
|
unary_term:
|
|
NUMBER maybe_space
|
|
| PERCENTAGE maybe_space
|
|
| LENGTH maybe_space
|
|
| ANGLE maybe_space
|
|
| TIME maybe_space
|
|
| FREQ maybe_space
|
|
;
|
|
|
|
function:
|
|
FUNCTION maybe_space expr ')' maybe_space {
|
|
$$.type = TYPE_FUNCTION; $$.function = $3;
|
|
$$.psz = $1;
|
|
if(*$$.psz != 0)
|
|
$$.psz[strlen($$.psz) - 1] = 0;
|
|
} |
|
|
FUNCTION maybe_space expr TOKEN_EOF {
|
|
$$.type = TYPE_FUNCTION; $$.function = $3; $$.psz = $1;
|
|
if(*$$.psz != 0)
|
|
$$.psz[strlen($$.psz) - 1] = 0;
|
|
} |
|
|
FUNCTION maybe_space ')' maybe_space {
|
|
$$.type = TYPE_FUNCTION; $$.function = NULL; $$.psz = $1;
|
|
if(*$$.psz != 0)
|
|
$$.psz[strlen($$.psz) - 1] = 0;
|
|
} |
|
|
FUNCTION maybe_space error {
|
|
$$.type = TYPE_FUNCTION; $$.function = NULL; $$.psz = $1;
|
|
if(*$$.psz != 0)
|
|
$$.psz[strlen($$.psz) - 1] = 0;
|
|
}
|
|
;
|
|
|
|
/* error handling rules */
|
|
|
|
invalid_rule:
|
|
error invalid_block {
|
|
$$ = NULL;
|
|
}
|
|
|
|
/*
|
|
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
|
|
;
|
|
|
|
%%
|
|
|
|
#ifdef YYDEBUG
|
|
int yydebug=1;
|
|
#else
|
|
int yydebug=0;
|
|
#endif
|
|
|