1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
%option prefix="expr_"
%option reentrant
%option bison-bridge
%{
#include <linux/compiler.h>
#include "expr.h"
#include "expr-bison.h"
char *expr_get_text(yyscan_t yyscanner);
YYSTYPE *expr_get_lval(yyscan_t yyscanner);
static int __value(YYSTYPE *yylval, char *str, int base, int token)
{
u64 num;
errno = 0;
num = strtoull(str, NULL, base);
if (errno)
return EXPR_ERROR;
yylval->num = num;
return token;
}
static int value(yyscan_t scanner, int base)
{
YYSTYPE *yylval = expr_get_lval(scanner);
char *text = expr_get_text(scanner);
return __value(yylval, text, base, NUMBER);
}
/*
* Allow @ instead of / to be able to specify pmu/event/ without
* conflicts with normal division.
*/
static char *normalize(char *str, int runtime)
{
char *ret = str;
char *dst = str;
while (*str) {
if (*str == '@')
*dst++ = '/';
else if (*str == '\\')
*dst++ = *++str;
else if (*str == '?') {
char *paramval;
int i = 0;
int size = asprintf(¶mval, "%d", runtime);
if (size < 0)
*dst++ = '0';
else {
while (i < size)
*dst++ = paramval[i++];
free(paramval);
}
}
else
*dst++ = *str;
str++;
}
*dst = 0x0;
return ret;
}
static int str(yyscan_t scanner, int token, int runtime)
{
YYSTYPE *yylval = expr_get_lval(scanner);
char *text = expr_get_text(scanner);
yylval->str = normalize(strdup(text), runtime);
if (!yylval->str)
return EXPR_ERROR;
yylval->str = normalize(yylval->str, runtime);
return token;
}
%}
number [0-9]+
sch [-,=]
spec \\{sch}
sym [0-9a-zA-Z_\.:@?]+
symbol {spec}*{sym}*{spec}*{sym}*{spec}*{sym}
%%
struct expr_scanner_ctx *sctx = expr_get_extra(yyscanner);
{
int start_token = sctx->start_token;
if (sctx->start_token) {
sctx->start_token = 0;
return start_token;
}
}
max { return MAX; }
min { return MIN; }
if { return IF; }
else { return ELSE; }
#smt_on { return SMT_ON; }
{number} { return value(yyscanner, 10); }
{symbol} { return str(yyscanner, ID, sctx->runtime); }
"|" { return '|'; }
"^" { return '^'; }
"&" { return '&'; }
"-" { return '-'; }
"+" { return '+'; }
"*" { return '*'; }
"/" { return '/'; }
"%" { return '%'; }
"(" { return '('; }
")" { return ')'; }
"," { return ','; }
. { }
%%
int expr_wrap(void *scanner __maybe_unused)
{
return 1;
}
|