1 /* Copyright (C) 2017 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
4 * Provide more verbose and specific error messages instead of just "syntax
7 %define parse.error verbose
10 * Verbose error messages may contain incorrect information if LAC (Lookahead
11 * Correction) is not enabled.
13 %define parse.lac full
15 /* Avoid symbol clashes (lopsub might also expose yy* symbols). */
16 %define api.prefix {mp_yy}
19 * Although locations are automatically enabled as soon as the grammar uses the
20 * special @N tokens, specifying %locations explicitly allows for more accurate
21 * syntax error messages.
26 * Generate a pure (reentrant) parser. With this option enabled, yylval and
27 * yylloc become local variables in yyparse(), and a different calling
28 * convention is used for yylex().
32 /* Additional arguments to yylex(), yyparse() and yyerror() */
33 %param {struct mp_context *ctx}
34 %param {struct mp_ast_node **ast}
35 %param {mp_yyscan_t yyscanner} /* reentrant lexers */
47 int yylex(MP_YYSTYPE *lvalp, MP_YYLTYPE *llocp, struct mp_context *ctx,
48 struct mp_ast_node **ast, mp_yyscan_t yyscanner);
49 static void yyerror(YYLTYPE *llocp, struct mp_context *ctx,
50 struct mp_ast_node **ast, mp_yyscan_t yyscanner, const char *msg);
60 static struct mp_ast_node *ast_node_raw(int id)
62 struct mp_ast_node *node = alloc(sizeof(struct mp_ast_node));
67 /* This is non-static because it is also called from the lexer. */
68 struct mp_ast_node *mp_new_ast_leaf_node(int id)
70 struct mp_ast_node *node = ast_node_raw(id);
71 node->num_children = 0;
75 static struct mp_ast_node *ast_node_new_unary(int id, struct mp_ast_node *child)
77 struct mp_ast_node *node = ast_node_raw(id);
78 node->num_children = 1;
79 node->children = alloc(sizeof(struct mp_ast_node *));
80 node->children[0] = child;
84 static struct mp_ast_node *ast_node_new_binary(int id, struct mp_ast_node *left,
85 struct mp_ast_node *right)
87 struct mp_ast_node *node = ast_node_raw(id);
88 node->num_children = 2;
89 node->children = arr_alloc(2, sizeof(struct mp_ast_node *));
90 node->children[0] = left;
91 node->children[1] = right;
95 void mp_free_ast(struct mp_ast_node *root)
99 if (root->num_children > 0) {
101 for (i = 0; i < root->num_children; i++)
102 mp_free_ast(root->children[i]);
103 free(root->children);
105 union mp_semantic_value *sv = &root->sv;
111 regfree(&sv->re_pattern.preg);
113 case WILDCARD_PATTERN:
114 free(sv->wc_pattern.pat);
121 static int eval_node(struct mp_ast_node *node, struct mp_context *ctx,
122 union mp_semantic_value *result);
124 static void eval_binary_op(struct mp_ast_node *node, struct mp_context *ctx,
125 union mp_semantic_value *v1, union mp_semantic_value *v2)
127 eval_node(node->children[0], ctx, v1);
128 eval_node(node->children[1], ctx, v2);
131 static int eval_node(struct mp_ast_node *node, struct mp_context *ctx,
132 union mp_semantic_value *result)
136 union mp_semantic_value v1, v2;
141 result->strval = node->sv.strval;
144 result->strval = mp_path(ctx);
147 result->strval = mp_artist(ctx);
150 result->strval = mp_title(ctx);
153 result->strval = mp_album(ctx);
156 result->strval = mp_comment(ctx);
160 result->intval = node->sv.intval;
163 eval_binary_op(node, ctx, &v1, &v2);
164 result->intval = v1.intval + v2.intval;
167 eval_binary_op(node, ctx, &v1, &v2);
168 result->intval = v1.intval - v2.intval;
171 eval_binary_op(node, ctx, &v1, &v2);
172 result->intval = v1.intval * v2.intval;
175 eval_binary_op(node, ctx, &v1, &v2);
176 if (v2.intval == 0) {
179 PARA_ERROR_LOG("division by zero\n");
183 result->intval = v1.intval / v2.intval;
186 eval_node(node->children[0], ctx, &v1);
187 result->intval = -v1.intval;
190 result->intval = mp_year(ctx);
192 case NUM_ATTRIBUTES_SET:
193 result->intval = mp_num_attributes_set(ctx);
196 result->intval = mp_num_played(ctx);
199 result->intval = mp_image_id(ctx);
202 result->intval = mp_lyrics_id(ctx);
205 result->intval = mp_bitrate(ctx);
208 result->intval = mp_frequency(ctx);
211 result->intval= mp_channels(ctx);
214 result->intval= mp_duration(ctx);
218 arg = node->children[0]->sv.strval;
219 result->boolval = mp_is_set(arg, ctx);
222 result->boolval = true;
225 result->boolval = false;
228 eval_binary_op(node, ctx, &v1, &v2);
229 result->boolval = v1.boolval || v2.boolval;
232 eval_binary_op(node, ctx, &v1, &v2);
233 result->boolval = v1.boolval && v2.boolval;
236 eval_node(node->children[0], ctx, &v1);
237 result->boolval = !v1.boolval;
240 ret = eval_node(node->children[0], ctx, &v1);
241 eval_node(node->children[1], ctx, &v2);
242 if (ret == ST_STRVAL)
243 result->boolval = !strcmp(v1.strval, v2.strval);
245 result->boolval = v1.intval == v2.intval;
248 ret = eval_node(node->children[0], ctx, &v1);
249 eval_node(node->children[1], ctx, &v2);
250 if (ret == ST_STRVAL)
251 result->boolval = strcmp(v1.strval, v2.strval);
253 result->boolval = v1.intval != v2.intval;
256 eval_binary_op(node, ctx, &v1, &v2);
257 result->boolval = v1.intval < v2.intval;
260 eval_binary_op(node, ctx, &v1, &v2);
261 result->boolval = v1.intval > v2.intval;
264 eval_binary_op(node, ctx, &v1, &v2);
265 result->boolval = v1.intval <= v2.intval;
267 case GREATER_OR_EQUAL:
268 eval_binary_op(node, ctx, &v1, &v2);
269 result->boolval = v1.intval >= v2.intval;
272 eval_binary_op(node, ctx, &v1, &v2);
273 result->boolval = fnmatch(v2.wc_pattern.pat, v1.strval,
274 v2.wc_pattern.flags) == 0;
277 eval_binary_op(node, ctx, &v1, &v2);
278 result->boolval = regexec(&v2.re_pattern.preg, v1.strval,
282 result->re_pattern = node->sv.re_pattern;
283 return ST_REGEX_PATTERN;
284 case WILDCARD_PATTERN:
285 result->wc_pattern = node->sv.wc_pattern;
286 return ST_WC_PATTERN;
288 PARA_EMERG_LOG("bug: invalid node id %d\n", node->id);
293 bool mp_eval_ast(struct mp_ast_node *root, struct mp_context *ctx)
295 union mp_semantic_value v;
296 int ret = eval_node(root, ctx, &v);
298 if (ret == ST_INTVAL)
299 return v.intval != 0;
300 if (ret == ST_STRVAL)
301 return v.strval[0] != 0;
302 if (ret == ST_BOOLVAL)
310 struct mp_ast_node *node;
315 %token <node> STRING_LITERAL
316 %token <node> REGEX_PATTERN
317 %token <node> WILDCARD_PATTERN
319 /* keywords with semantic value */
324 %token <node> COMMENT
326 %token <node> NUM_ATTRIBUTES_SET
327 %token <node> NUM_PLAYED
328 %token <node> IMAGE_ID
329 %token <node> LYRICS_ID
330 %token <node> BITRATE
331 %token <node> FREQUENCY
332 %token <node> CHANNELS
333 %token <node> DURATION
334 %token <node> FALSE TRUE
336 /* keywords without semantic value */
339 /* operators, ordered by precendence */
342 %left EQUAL NOT_EQUAL
343 %left LESS_THAN LESS_OR_EQUAL GREATER_OR_EQUAL REGEX_MATCH FILENAME_MATCH
346 %right NOT NEG /* negation (unary minus) */
356 /* empty */ {*ast = NULL; return 0;}
357 | string {*ast = $1; return 0;}
358 | exp {*ast = $1; return 0;}
359 | boolexp {*ast = $1; return 0;}
361 string: STRING_LITERAL {$$ = $1;}
362 | PATH {$$ = mp_new_ast_leaf_node(PATH);}
363 | ARTIST {$$ = mp_new_ast_leaf_node(ARTIST);}
364 | TITLE {$$ = mp_new_ast_leaf_node(TITLE);}
365 | ALBUM {$$ = mp_new_ast_leaf_node(ALBUM);}
366 | COMMENT {$$ = mp_new_ast_leaf_node(COMMENT);}
370 | exp '+' exp {$$ = ast_node_new_binary('+', $1, $3);}
371 | exp '-' exp {$$ = ast_node_new_binary('-', $1, $3);}
372 | exp '*' exp {$$ = ast_node_new_binary('*', $1, $3);}
373 | exp '/' exp {$$ = ast_node_new_binary('/', $1, $3);}
374 | '-' exp %prec NEG {$$ = ast_node_new_unary(NEG, $2);}
375 | '(' exp ')' {$$ = $2;}
376 | YEAR {$$ = mp_new_ast_leaf_node(YEAR);}
377 | NUM_ATTRIBUTES_SET {$$ = mp_new_ast_leaf_node(NUM_ATTRIBUTES_SET);}
378 | NUM_PLAYED {$$ = mp_new_ast_leaf_node(NUM_PLAYED);}
379 | IMAGE_ID {$$ = mp_new_ast_leaf_node(IMAGE_ID);}
380 | LYRICS_ID {$$ = mp_new_ast_leaf_node(LYRICS_ID);}
381 | BITRATE {$$ = mp_new_ast_leaf_node(BITRATE);}
382 | FREQUENCY {$$ = mp_new_ast_leaf_node(FREQUENCY);}
383 | CHANNELS {$$ = mp_new_ast_leaf_node(CHANNELS);}
384 | DURATION {$$ = mp_new_ast_leaf_node(DURATION);}
387 boolexp: IS_SET '(' STRING_LITERAL ')' {$$ = ast_node_new_unary(IS_SET, $3);}
388 | TRUE {$$ = mp_new_ast_leaf_node(TRUE);}
389 | FALSE {$$ = mp_new_ast_leaf_node(FALSE);}
390 | '(' boolexp ')' {$$ = $2;}
391 | boolexp OR boolexp {$$ = ast_node_new_binary(OR, $1, $3);}
392 | boolexp AND boolexp {$$ = ast_node_new_binary(AND, $1, $3);}
393 | NOT boolexp {$$ = ast_node_new_unary(NOT, $2);}
394 | exp EQUAL exp {$$ = ast_node_new_binary(EQUAL, $1, $3);}
395 | exp NOT_EQUAL exp {$$ = ast_node_new_binary(NOT_EQUAL, $1, $3);}
396 | exp '<' exp {$$ = ast_node_new_binary('<', $1, $3);}
397 | exp '>' exp {$$ = ast_node_new_binary('>', $1, $3);}
398 | exp LESS_OR_EQUAL exp {
399 $$ = ast_node_new_binary(LESS_OR_EQUAL, $1, $3);
401 | exp GREATER_OR_EQUAL exp {
402 $$ = ast_node_new_binary(GREATER_OR_EQUAL, $1, $3);
404 | string REGEX_MATCH REGEX_PATTERN {
405 $$ = ast_node_new_binary(REGEX_MATCH, $1, $3);
407 | string FILENAME_MATCH WILDCARD_PATTERN {
408 $$ = ast_node_new_binary(FILENAME_MATCH, $1, $3);
410 | string EQUAL string {$$ = ast_node_new_binary(EQUAL, $1, $3);}
411 | string NOT_EQUAL string {$$ = ast_node_new_binary(NOT_EQUAL, $1, $3);}
415 /* Called by yyparse() on error */
416 static void yyerror(YYLTYPE *llocp, struct mp_context *ctx,
417 struct mp_ast_node **ast, mp_yyscan_t yyscanner, const char *msg)
419 mp_parse_error(llocp->first_line, ctx, "%s", msg);