yambar/particles/map.y
Leonardo Gibrowski Faé 4a41d4296a
Implement '&&' and '||' operators on map
'-' is a valid character for tags.

Commit 03e1c7d (module/network: Add link stats, 2022-04-30) introduced
two new tags for the network module: `ul-speed` and `dl-speed`. These
use the `-` character, that was previously never used in any tag.

We had two options: either change those tags to use `_` instead, or just
accept `-`s as a valid character. Going forward, I can see many people
deciding to name their tags with `-` instead of `_`, so I believe it is
better to just accept it once and for all.

Note that `-` cannot be used as the first character of a tag (e.g.
`-tag1`) since the `-` has a special meaning in `.yml` files. I don't
believe this will happen often, however, and should be easy to both
detect and correct if it does.
2022-12-10 22:53:30 -03:00

125 lines
3.2 KiB
Text

%{
#include <stdio.h>
#include <string.h>
#include "map.h"
struct map_condition *MAP_CONDITION_PARSE_RESULT;
char *MAP_PARSER_ERROR_MSG;
static const int NUM_TOKENS = 7;
int yylex();
void yyerror(const char *str);
%}
%define parse.lac full
%define parse.error custom
%union {
char *str;
struct map_condition *condition;
enum map_op op;
}
%token WORD STRING CMP_OP L_PAR R_PAR
%left BOOL_OP
%precedence NOT
%destructor { free_map_condition($<condition>$); } condition
%destructor { free($<str>$); } WORD
%destructor { free($<str>$); } STRING
%%
result: condition { MAP_CONDITION_PARSE_RESULT = $<condition>1; };
condition:
WORD {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->tag = $<str>1;
$<condition>$->op = MAP_OP_SELF;
}
|
WORD CMP_OP WORD {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->tag = $<str>1;
$<condition>$->op = $<op>2;
$<condition>$->value = $<str>3;
}
|
WORD CMP_OP STRING {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->tag = $<str>1;
$<condition>$->op = $<op>2;
$<condition>$->value = $<str>3;
}
|
L_PAR condition R_PAR { $<condition>$ = $<condition>2; }
|
NOT condition {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->cond1 = $<condition>2;
$<condition>$->op = MAP_OP_NOT;
}
|
condition BOOL_OP condition {
$<condition>$ = malloc(sizeof(struct map_condition));
$<condition>$->cond1 = $<condition>1;
$<condition>$->op = $<op>2;
$<condition>$->cond2 = $<condition>3;
}
;
%%
void yyerror(const char *str)
{
fprintf(stderr, "error: %s\n", str);
}
static char const*
token_to_str(yysymbol_kind_t tkn)
{
switch (tkn) {
case YYSYMBOL_CMP_OP: return "==, !=, <=, <, >=, >";
case YYSYMBOL_BOOL_OP: return "||, &&";
case YYSYMBOL_L_PAR: return "(";
case YYSYMBOL_R_PAR: return ")";
case YYSYMBOL_NOT: return "~";
default: return yysymbol_name(tkn);
}
}
static int
yyreport_syntax_error (const yypcontext_t *ctx)
{
int res = 0;
char *errmsg = malloc(1024);
errmsg[0] = '\0';
// Report the tokens expected at this point.
yysymbol_kind_t expected[NUM_TOKENS];
int n = yypcontext_expected_tokens(ctx, expected, NUM_TOKENS);
if (n < 0)
res = n; // Forward errors to yyparse.
else {
for (int i = 0; i < n; ++i) {
strcat(errmsg, i == 0 ? "expected [" : ", ");
strcat(errmsg, token_to_str(expected[i]));
}
strcat(errmsg, "]");
}
// Report the unexpected token.
yysymbol_kind_t lookahead = yypcontext_token(ctx);
if (lookahead != YYSYMBOL_YYEMPTY) {
strcat(errmsg, ", found ");
if (!(lookahead == YYSYMBOL_STRING || lookahead == YYSYMBOL_WORD))
strcat(errmsg, yysymbol_name(lookahead));
else if (yylval.str != NULL)
strcat(errmsg, yylval.str);
else
strcat(errmsg, "nothing");
}
MAP_PARSER_ERROR_MSG = errmsg;
return res;
}