/* * Hic Est Leo -- MapCSS Parser * * (c) 2014 Martin Mares */ %{ #include #include #include #include #include "leo.h" #include "css.h" static void *css_alloc(size_t n) { return mp_alloc_zero(css_this->pool, n); } static struct css_path *css_new_path(void) { struct css_path *p = css_alloc(sizeof(struct css_path)); clist_init(&p->conditions); p->layer = STYLE_LAYER_DEFAULT; return p; } static void css_add_to_val_list(struct style_prop *list, struct style_prop *elt) { struct style_val_list_entry *e = css_alloc(sizeof(*e)); clist_add_tail(list->val.list, &e->n); e->val = *elt; } %} %union { char *s; struct css_rule *rule; struct css_selector *selector; struct css_path *path; struct css_condition *condition; struct css_action *action; struct style_prop prop; enum css_cond_op cond_op; } %token LE GE NE CC %token NUMBER IDENT QUOTED RGB %type ident_or_quoted %type rule rule_start rule_selectors rule_start_actions rule_actions %type selector selector_start %type path path_start path_conditions %type condition %type action %type prop_value prop_value_single prop_value_list %type binary_op %% input: /* empty */ | input rule { clist_add_tail(&css_this->rules, &$2->n); } ; rule_start: /* empty */ { $$ = css_alloc(sizeof(struct css_rule)); clist_init(&$$->selectors); clist_init(&$$->actions); } ; rule_selectors: rule_start selector { clist_add_tail(&$1->selectors, &$2->n); $$ = $1; } | rule_selectors ',' selector { clist_add_tail(&$1->selectors, &$3->n); $$ = $1; } ; rule_start_actions: rule_start | rule_selectors ; rule_actions: rule_start_actions '{' { $$ = $1; } | rule_actions action ';' { $$ = $1; clist_add_tail(&$$->actions, &$2->n); } ; rule: rule_actions '}' ; selector_start: /* empty */ { $$ = css_alloc(sizeof(struct css_selector)); clist_init(&$$->path); } ; selector: selector_start path { clist_add_tail(&$1->path, &$2->n); $$ = $1; } | selector path { // FIXME: Descendant operator clist_add_tail(&$1->path, &$2->n); $$ = $1; } ; path_start: IDENT { $$ = css_new_path(); if (!strcmp($1, "node")) $$->type = CSS_TYPE_NODE; else if (!strcmp($1, "way")) $$->type = CSS_TYPE_WAY; else if (!strcmp($1, "relation")) $$->type = CSS_TYPE_RELATION; else if (!strcmp($1, "area")) $$->type = CSS_TYPE_AREA; else if (!strcmp($1, "meta")) $$->type = CSS_TYPE_META; else die("Invalid selector %s", $1); } | '*' { $$ = css_new_path(); $$->type = CSS_TYPE_ANY; } ; path_conditions: path_start | path_conditions '[' condition ']' { $$ = $1; clist_add_tail(&$$->conditions, &$3->n); } ; path: path_conditions | path ':' IDENT { // So far, no modifiers are supported, so a rule with modifiers never matches $$ = $1; $$->modifiers |= PATH_MOD_NEVER; } | path CC IDENT { // Layer $$ = $1; $$->layer = style_layer_encode($3); } | path CC '*' { // All layers $$ = $1; $$->layer = STYLE_LAYER_ALL; } ; condition: ident_or_quoted binary_op ident_or_quoted { $$ = css_alloc(sizeof(struct css_condition)); $$->op = $2; $$->key = osm_key_encode($1); $$->val = osm_val_encode($3); } | ident_or_quoted { $$ = css_alloc(sizeof(struct css_condition)); $$->op = COND_OP_IS_SET; $$->key = osm_key_encode($1); } | '!' ident_or_quoted { $$ = css_alloc(sizeof(struct css_condition)); $$->op = COND_OP_IS_UNSET; $$->key = osm_key_encode($2); } | ident_or_quoted '?' { $$ = css_alloc(sizeof(struct css_condition)); $$->op = COND_OP_IS_TRUE; $$->key = osm_key_encode($1); } | ident_or_quoted '?' '!' { $$ = css_alloc(sizeof(struct css_condition)); $$->op = COND_OP_IS_FALSE; $$->key = osm_key_encode($1); } ; binary_op: '=' { $$ = COND_OP_EQ; } | '<' { $$ = COND_OP_LT; } | '>' { $$ = COND_OP_GT; } | LE { $$ = COND_OP_LE; } | GE { $$ = COND_OP_GE; } | NE { $$ = COND_OP_NE; } ; action: ident_or_quoted ':' prop_value { $$ = css_alloc(sizeof(struct css_action)); $$->prop = $3; $$->prop.key = style_prop_encode($1); } ; prop_value: prop_value_single | prop_value_list ; prop_value_single: IDENT { $$.type = PROP_TYPE_IDENT; $$.val.id = osm_val_encode($1); } | QUOTED { $$.type = PROP_TYPE_STRING; $$.val.id = osm_val_encode($1); } | NUMBER { $$.type = PROP_TYPE_NUMBER; $$.val.number = atof($1); } | RGB { $$.type = PROP_TYPE_COLOR; $$.val.color = css_rgb_to_color($1); } ; prop_value_list: prop_value_single ',' prop_value_single { $$.type = PROP_TYPE_LIST; $$.val.list = css_alloc(sizeof(clist)); clist_init($$.val.list); css_add_to_val_list(&$$, &$1); css_add_to_val_list(&$$, &$3); } | prop_value_list ',' prop_value_single { $$ = $1; css_add_to_val_list(&$$, &$3); } ; ident_or_quoted: IDENT | QUOTED ; %% struct css_sheet *css_this; struct css_sheet *css_load(char *filename) { struct mempool *mp = mp_new(4096); struct css_sheet *ss = mp_alloc_zero(mp, sizeof(*ss)); ss->pool = mp; clist_init(&ss->rules); ss->filename = mp_strdup(mp, filename); css_this = ss; css_lex_open(); css_parse(); css_lex_close(); css_this = NULL; return ss; }