588 lines
13 KiB
Text
588 lines
13 KiB
Text
%{
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "css_lex.h"
|
|
#include "parser.h"
|
|
|
|
#define YYPARSE_PARAM yyparam
|
|
#define YYERROR_VERBOSE 1
|
|
//#define YYDEBUG 1
|
|
|
|
%}
|
|
|
|
%pure_parser
|
|
|
|
%union {
|
|
char *lexeme;
|
|
char letter;
|
|
struct property_t *property;
|
|
struct selector_t *selector;
|
|
struct selector_list_t *selector_list;
|
|
int pseudo_class;
|
|
int pseudo_element;
|
|
}
|
|
|
|
%token IMPORT_SYM
|
|
%token IMPORTANT_SYM
|
|
%token IDENT
|
|
%token STRING
|
|
%token NUMBER
|
|
%token PERCENTAGE
|
|
%token LENGTH
|
|
%token EMS
|
|
%token EXS
|
|
%token LINK_PSCLASS_AFTER_IDENT
|
|
%token VISITED_PSCLASS_AFTER_IDENT
|
|
%token ACTIVE_PSCLASS_AFTER_IDENT
|
|
%token FIRST_LINE_AFTER_IDENT
|
|
%token FIRST_LETTER_AFTER_IDENT
|
|
%token HASH_AFTER_IDENT
|
|
%token CLASS_AFTER_IDENT
|
|
%token LINK_PSCLASS
|
|
%token VISITED_PSCLASS
|
|
%token ACTIVE_PSCLASS
|
|
%token FIRST_LINE
|
|
%token FIRST_LETTER
|
|
%token HASH
|
|
%token CLASS
|
|
%token URL
|
|
%token RGB
|
|
%token CDO
|
|
%token CDC
|
|
%token CSL
|
|
|
|
%type <pseudo_class> solitary_pseudo_class
|
|
%type <pseudo_class> pseudo_class
|
|
%type <selector> selector
|
|
%type <selector> simple_selector
|
|
%type <selector> simple_selectors
|
|
%type <selector_list> selectors
|
|
%type <selector_list> ruleset
|
|
%type <selector_list> rulesets
|
|
%type <pseudo_element> pseudo_element
|
|
%type <selector> solitary_pseudo_element
|
|
%type <letter> unary_operator
|
|
%type <letter> operator
|
|
%type <property> declaration
|
|
%type <property> declarations
|
|
%type <lexeme> NUMBER
|
|
%type <lexeme> STRING
|
|
%type <lexeme> PERCENTAGE
|
|
%type <lexeme> LENGTH
|
|
%type <lexeme> EMS
|
|
%type <lexeme> EXS
|
|
%type <lexeme> URL
|
|
%type <lexeme> RGB
|
|
%type <lexeme> IDENT
|
|
%type <lexeme> HASH
|
|
%type <lexeme> HASH_AFTER_IDENT
|
|
%type <lexeme> CLASS_AFTER_IDENT
|
|
%type <lexeme> CLASS
|
|
%type <lexeme> hexcolor
|
|
%type <lexeme> value
|
|
%type <lexeme> id
|
|
%type <lexeme> solitary_id
|
|
%type <lexeme> term
|
|
%type <lexeme> property
|
|
%type <lexeme> expr
|
|
%type <lexeme> element_name
|
|
%type <lexeme> class
|
|
%type <lexeme> solitary_class
|
|
%type <lexeme> string_or_url
|
|
|
|
%%
|
|
|
|
stylesheet
|
|
: comments imports rulesets {
|
|
*(struct selector_list_t**) yyparam = $3;
|
|
}
|
|
;
|
|
|
|
rulesets
|
|
: ruleset comments rulesets {
|
|
struct selector_list_t *pos = $1;
|
|
if (pos != NULL) {
|
|
while (pos->next != NULL) {
|
|
pos = pos->next;
|
|
}
|
|
pos->next = $3;
|
|
} else {
|
|
$1 = $3;
|
|
}
|
|
$$ = $1;
|
|
}
|
|
| { $$ = NULL; }
|
|
;
|
|
|
|
imports
|
|
: import comments imports
|
|
|
|
|
;
|
|
|
|
comments
|
|
: comments comment
|
|
|
|
|
;
|
|
|
|
comment
|
|
: CDO
|
|
| CDC
|
|
| CSL
|
|
;
|
|
|
|
import
|
|
: IMPORT_SYM string_or_url ';' /* E.g., @import url(fun.css); */
|
|
;
|
|
|
|
string_or_url
|
|
: STRING { $$ = $1; }
|
|
| URL {
|
|
char *begin = $1;
|
|
char *end = $1 + strlen($1);
|
|
|
|
/* Skip url( */
|
|
begin += 4;
|
|
/* skip whitespace */
|
|
while (*begin == ' ')
|
|
++begin;
|
|
|
|
/* Skip ) */
|
|
end -= 2;
|
|
/* skip whitespace */
|
|
while (*end == ' ')
|
|
--end;
|
|
|
|
end[1] = 0;
|
|
|
|
$$ = strdup(begin);
|
|
free($1);
|
|
}
|
|
;
|
|
|
|
unary_operator
|
|
: '-' { $$ = '-'; }
|
|
| '+' { $$ = '+'; }
|
|
;
|
|
|
|
operator
|
|
: '/' { $$ = '/'; }
|
|
| ',' { $$ = ','; }
|
|
| /* empty */ {$$ = ' '; }
|
|
;
|
|
|
|
property
|
|
: IDENT { $$ = $1; }
|
|
;
|
|
|
|
ruleset
|
|
: selectors '{' declarations '}' {
|
|
struct selector_list_t *pos = $1;
|
|
while (pos != NULL) {
|
|
struct property_t *i = $3;
|
|
while (i != NULL) {
|
|
i->count++;
|
|
i = i->next;
|
|
}
|
|
pos->selector->property = $3;
|
|
pos = pos->next;
|
|
}
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
selectors
|
|
: selector {
|
|
if ($1 != NULL) {
|
|
$$ = (struct selector_list_t*)
|
|
malloc (sizeof(struct selector_list_t));
|
|
$$->selector = $1;
|
|
$$->next = NULL;
|
|
} else {
|
|
$$ = NULL;
|
|
}
|
|
}
|
|
| selector ',' selectors {
|
|
if ($1 != NULL) {
|
|
struct selector_list_t *new;
|
|
new = (struct selector_list_t*)
|
|
malloc (sizeof(struct selector_list_t));
|
|
new->selector = $1;
|
|
new->next = $3;
|
|
$$ = new;
|
|
} else {
|
|
$$ = $3;
|
|
}
|
|
}
|
|
;
|
|
|
|
declarations
|
|
: declaration {
|
|
$$ = $1;
|
|
}
|
|
| declaration ';' declarations {
|
|
if ($1 != NULL) {
|
|
$1->next = $3;
|
|
$$ = $1;
|
|
} else {
|
|
$$ = $3;
|
|
}
|
|
}
|
|
;
|
|
|
|
selector
|
|
: simple_selectors pseudo_element {
|
|
struct selector_t *pos = $1;
|
|
while (pos->next != NULL) {
|
|
pos = pos->next;
|
|
}
|
|
pos->pseudo_element = $2;
|
|
$$ = $1;
|
|
}
|
|
| simple_selectors solitary_pseudo_element {
|
|
struct selector_t *pos = $1;
|
|
while (pos->next != NULL) {
|
|
pos = pos->next;
|
|
}
|
|
pos->next = $2;
|
|
$$ = $1;
|
|
}
|
|
| simple_selectors { $$ = $1; }
|
|
| solitary_pseudo_element { $$ = $1; }
|
|
| selector error { $$ = NULL; }
|
|
| error { $$ = NULL; }
|
|
;
|
|
|
|
simple_selectors
|
|
: simple_selector { $$ = $1; }
|
|
| simple_selector simple_selectors {
|
|
$1->next = $2;
|
|
$$ = $1;
|
|
}
|
|
;
|
|
|
|
/* An "id" is an ID that is attached to an element type
|
|
** on its left, as in: P#p007
|
|
** A "solitary_id" is an ID that is not so attached,
|
|
** as in: #p007
|
|
** Analogously for classes and pseudo-classes.
|
|
*/
|
|
simple_selector
|
|
: element_name id class pseudo_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = $1;
|
|
$$->id = $2;
|
|
$$->e_class = $3;
|
|
$$->pseudo_class = $4;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
} /* eg: H1.subject */
|
|
| element_name id pseudo_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = $1;
|
|
$$->id = $2;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = $3;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| element_name class pseudo_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = $1;
|
|
$$->id = NULL;
|
|
$$->e_class = $2;
|
|
$$->pseudo_class = $3;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| element_name id class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = $1;
|
|
$$->id = $2;
|
|
$$->e_class = $3;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| element_name id {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = $1;
|
|
$$->id = $2;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| element_name class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = $1;
|
|
$$->id = NULL;
|
|
$$->e_class = $2;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| element_name pseudo_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = $1;
|
|
$$->id = NULL;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = $2;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| element_name {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = $1;
|
|
$$->id = NULL;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| solitary_id class pseudo_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = $1;
|
|
$$->e_class = $2;
|
|
$$->pseudo_class = $3;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
} /* eg: #xyz33 */
|
|
| solitary_id class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = $1;
|
|
$$->e_class = $2;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| solitary_id pseudo_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = $1;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = $2;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| solitary_id {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = $1;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| solitary_class pseudo_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = NULL;
|
|
$$->e_class = $1;
|
|
$$->pseudo_class = $2;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}/* eg: .author */
|
|
| solitary_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = NULL;
|
|
$$->e_class = $1;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| solitary_pseudo_class {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = NULL;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = $1;
|
|
$$->pseudo_element = 0;
|
|
$$->next = NULL;
|
|
} /* eg: :link */
|
|
;
|
|
|
|
element_name
|
|
: IDENT { $$ = $1; }
|
|
;
|
|
|
|
pseudo_class /* as in: A:link */
|
|
: LINK_PSCLASS_AFTER_IDENT { $$ = PS_CLASS_LINK; }
|
|
| VISITED_PSCLASS_AFTER_IDENT { $$ = PS_CLASS_VISITED; }
|
|
| ACTIVE_PSCLASS_AFTER_IDENT { $$ = PS_CLASS_ACTIVE; }
|
|
;
|
|
|
|
solitary_pseudo_class /* as in: :link */
|
|
: LINK_PSCLASS { $$ = PS_CLASS_LINK; }
|
|
| VISITED_PSCLASS { $$ = PS_CLASS_VISITED; }
|
|
| ACTIVE_PSCLASS { $$ = PS_CLASS_ACTIVE; }
|
|
;
|
|
|
|
class /* as in: P.note */
|
|
: CLASS_AFTER_IDENT { $$ = $1; }
|
|
;
|
|
|
|
solitary_class /* as in: .note */
|
|
: CLASS { $$ = $1; }
|
|
;
|
|
|
|
pseudo_element /* as in: P:first-line */
|
|
: FIRST_LETTER_AFTER_IDENT { $$ = PS_ELEMENT_FIRST_LETTER; }
|
|
| FIRST_LINE_AFTER_IDENT { $$ = PS_ELEMENT_FIRST_LINE; }
|
|
;
|
|
|
|
solitary_pseudo_element /* as in: :first-line */
|
|
: FIRST_LETTER {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = NULL;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = PS_ELEMENT_FIRST_LETTER;
|
|
$$->next = NULL;
|
|
}
|
|
| FIRST_LINE {
|
|
$$ = (struct selector_t*)
|
|
malloc(sizeof(struct selector_t));
|
|
$$->element_name = NULL;
|
|
$$->id = NULL;
|
|
$$->e_class = NULL;
|
|
$$->pseudo_class = 0;
|
|
$$->pseudo_element = PS_ELEMENT_FIRST_LINE;
|
|
$$->next = NULL;
|
|
}
|
|
;
|
|
|
|
/* There is a constraint on the id and solitary_id that the
|
|
** part after the "#" must be a valid HTML ID value;
|
|
** e.g., "#x77" is OK, but "#77" is not.
|
|
*/
|
|
id
|
|
: HASH_AFTER_IDENT { $$ = $1; }
|
|
;
|
|
|
|
solitary_id
|
|
: HASH { $$ = $1; }
|
|
;
|
|
|
|
declaration
|
|
: property ':' expr prio {
|
|
$$ = (struct property_t*)
|
|
malloc(sizeof(struct property_t));
|
|
$$->name = $1;
|
|
$$->val = $3;
|
|
$$->important = 1;
|
|
$$->count = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| property ':' expr {
|
|
$$ = (struct property_t*)
|
|
malloc(sizeof(struct property_t));
|
|
$$->name = $1;
|
|
$$->val = $3;
|
|
$$->important = 0;
|
|
$$->count = 0;
|
|
$$->next = NULL;
|
|
}
|
|
| error { $$ = NULL; }
|
|
| /* empty */ {
|
|
$$ = NULL;
|
|
} /* Prevents syntax errors... */
|
|
;
|
|
|
|
prio
|
|
: IMPORTANT_SYM { } /* !important */
|
|
;
|
|
|
|
expr
|
|
: term { $$ = $1; }
|
|
| expr operator term {
|
|
char *s = (char*) malloc (strlen($1)+strlen($3)+2);
|
|
strcpy(s, $1);
|
|
s[strlen(s)+1] = 0;
|
|
s[strlen(s)] = $2;
|
|
strcat(s, $3);
|
|
free($1);
|
|
free($3);
|
|
$$ = s;
|
|
}
|
|
| expr error { $$ = $1; }
|
|
;
|
|
|
|
term
|
|
: unary_operator value {
|
|
char *s = (char*) malloc(strlen($2)+2);
|
|
s[0] = $1;
|
|
s[1] = 0;
|
|
strcat(s, $2);
|
|
free($2);
|
|
$$ = s;
|
|
}
|
|
| value { $$ = $1; }
|
|
;
|
|
|
|
value
|
|
: NUMBER { $$ = $1; }
|
|
| STRING { $$ = $1; }
|
|
| PERCENTAGE { $$ = $1; }
|
|
| LENGTH { $$ = $1; }
|
|
| EMS { $$ = $1; }
|
|
| EXS { $$ = $1; }
|
|
| IDENT { $$ = $1; }
|
|
| hexcolor { $$ = $1; }
|
|
| URL { $$ = $1; }
|
|
| RGB { $$ = $1; }
|
|
;
|
|
|
|
/* 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
|
|
: HASH {
|
|
$$ = (char*) malloc (strlen($1)+2);
|
|
sprintf($$, "#%s", $1);
|
|
free($1);
|
|
}
|
|
| HASH_AFTER_IDENT {
|
|
$$ = (char*) malloc (strlen($1)+2);
|
|
sprintf($$, "#%s", $1);
|
|
free($1);
|
|
}
|
|
;
|
|
|
|
%%
|
|
|
|
int yyerror(char *s) {
|
|
#if YYDEBUG
|
|
fprintf(stderr, "Error: %s\n", s);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
struct selector_list_t* css_parse(const char *buffer, int buf_len) {
|
|
struct selector_list_t *ret = NULL;
|
|
//yydebug = 1;
|
|
init_yylex(buffer, buf_len);
|
|
yyparse(&ret);
|
|
end_yylex();
|
|
return ret;
|
|
}
|