-/* $OpenBSD: bt_parse.y,v 1.56 2023/12/20 14:00:17 dv Exp $ */
+/* $OpenBSD: bt_parse.y,v 1.57 2024/01/16 14:35:56 claudio Exp $ */
/*
* Copyright (c) 2019-2023 Martin Pieuchot <mpi@openbsd.org>
/* Functions and Map operators */
%token <v.i> F_DELETE F_PRINT
%token <v.i> MFUNC FUNC0 FUNC1 FUNCN OP1 OP2 OP4 MOP0 MOP1
-%token <v.string> STRING CSTRING
+%token <v.string> STRING CSTRING GVAR LVAR
+%token <v.arg> PVAR PNUM
%token <v.number> NUMBER
-%type <v.string> gvar lvar
%type <v.i> beginend
%type <v.probe> plist probe pname
%type <v.filter> filter
%type <v.stmt> action stmt stmtblck stmtlist block
-%type <v.arg> vargs mentry mpat pargs staticv
+%type <v.arg> vargs mentry mpat pargs
%type <v.arg> expr term fterm variable factor func
%%
| STRING ':' HZ ':' NUMBER { $$ = bp_new($1, "hz", NULL, $5); }
;
-staticv : '$' NUMBER { $$ = get_varg($2); }
- | '$' '#' { $$ = get_nargs(); }
- ;
-
-gvar : '@' STRING { $$ = $2; }
- | '@' { $$ = UNNAMED_MAP; }
- ;
-
-lvar : '$' STRING { $$ = $2; }
- ;
-
-mentry : gvar '[' vargs ']' { $$ = bm_find($1, $3); }
+mentry : GVAR '[' vargs ']' { $$ = bm_find($1, $3); }
;
mpat : MOP0 '(' ')' { $$ = ba_new(NULL, $1); }
| factor
;
-variable: lvar { $$ = bl_find($1); }
- | gvar { $$ = bg_find($1); }
+variable: LVAR { $$ = bl_find($1); }
+ | GVAR { $$ = bg_find($1); }
| variable '.' NUMBER { $$ = bi_find($1, $3); }
;
| NUMBER { $$ = ba_new($1, B_AT_LONG); }
| BUILTIN { $$ = ba_new(NULL, $1); }
| CSTRING { $$ = ba_new($1, B_AT_STR); }
- | staticv
+ | PVAR
+ | PNUM
| variable
| mentry
| func
;
-func : STR '(' staticv ')' { $$ = ba_new($3, B_AT_FN_STR); }
- | STR '(' staticv ',' expr ')' { $$ = ba_op(B_AT_FN_STR, $3, $5); }
+func : STR '(' PVAR ')' { $$ = ba_new($3, B_AT_FN_STR); }
+ | STR '(' PVAR ',' expr ')' { $$ = ba_op(B_AT_FN_STR, $3, $5); }
;
vargs : expr
;
pargs : expr
- | gvar ',' expr { $$ = ba_append(bg_find($1), $3); }
+ | GVAR ',' expr { $$ = ba_append(bg_find($1), $3); }
;
NL : /* empty */
;
stmt : ';' NL { $$ = NULL; }
- | gvar '=' expr { $$ = bg_store($1, $3); }
- | lvar '=' expr { $$ = bl_store($1, $3); }
- | gvar '[' vargs ']' '=' mpat { $$ = bm_insert($1, $3, $6); }
+ | GVAR '=' expr { $$ = bg_store($1, $3); }
+ | LVAR '=' expr { $$ = bl_store($1, $3); }
+ | GVAR '[' vargs ']' '=' mpat { $$ = bm_insert($1, $3, $6); }
| FUNCN '(' vargs ')' { $$ = bs_new($1, $3, NULL); }
| FUNC1 '(' expr ')' { $$ = bs_new($1, $3, NULL); }
| MFUNC '(' variable ')' { $$ = bs_new($1, $3, NULL); }
| FUNC0 '(' ')' { $$ = bs_new($1, NULL, NULL); }
| F_DELETE '(' mentry ')' { $$ = bm_op($1, $3, NULL); }
| F_PRINT '(' pargs ')' { $$ = bs_new($1, $3, NULL); }
- | gvar '=' OP1 '(' expr ')' { $$ = bh_inc($1, $5, NULL); }
- | gvar '=' OP4 '(' expr ',' vargs ')' { $$ = bh_inc($1, $5, $7); }
+ | GVAR '=' OP1 '(' expr ')' { $$ = bh_inc($1, $5, NULL); }
+ | GVAR '=' OP4 '(' expr ',' vargs ')' { $$ = bh_inc($1, $5, $7); }
;
stmtblck: IF '(' expr ')' block { $$ = bt_new($3, $5); }
const char *errstr = NULL;
long val;
- if (0 < index && index <= nargs) {
+ if (1 <= index && index <= nargs) {
val = (long)strtonum(vargs[index-1], LONG_MIN, LONG_MAX,
&errstr);
if (errstr == NULL)
}
}
+static inline int
+allowed_to_end_number(int x)
+{
+ return (isspace(x) || x == ')' || x == '/' || x == '{' || x == ';' ||
+ x == ']' || x == ',' || x == '=');
+}
+
+static inline int
+allowed_in_string(int x)
+{
+ return (isalnum(x) || x == '_');
+}
+
int
yylex(void)
{
case ':':
case ';':
return c;
+ case '$':
+ c = lgetc();
+ if (c == '#') {
+ yylval.v.arg = get_nargs();
+ return PNUM;
+ } else if (isdigit(c)) {
+ do {
+ *p++ = c;
+ if (p == ebuf) {
+ yyerror("line too long");
+ return ERROR;
+ }
+ } while ((c = lgetc()) != EOF && isdigit(c));
+ lungetc();
+ *p = '\0';
+ if (c == EOF || allowed_to_end_number(c)) {
+ const char *errstr = NULL;
+ int num;
+
+ num = strtonum(buf, 1, INT_MAX, &errstr);
+ if (errstr) {
+ yyerror("'$%s' is %s", buf, errstr);
+ return ERROR;
+ }
+
+ yylval.v.arg = get_varg(num);
+ return PVAR;
+ }
+ } else if (isalpha(c)) {
+ do {
+ *p++ = c;
+ if (p == ebuf) {
+ yyerror("line too long");
+ return ERROR;
+ }
+ } while ((c = lgetc()) != EOF && allowed_in_string(c));
+ lungetc();
+ *p = '\0';
+ if ((yylval.v.string = strdup(buf)) == NULL)
+ err(1, "%s", __func__);
+ return LVAR;
+ }
+ yyerror("'$%s%c' is an invalid variable name", buf, c);
+ return ERROR;
+ break;
+ case '@':
+ c = lgetc();
+ /* check for unnamed map '@' */
+ if (isalpha(c)) {
+ do {
+ *p++ = c;
+ if (p == ebuf) {
+ yyerror("line too long");
+ return ERROR;
+ }
+ } while ((c = lgetc()) != EOF && allowed_in_string(c));
+ lungetc();
+ *p = '\0';
+ if ((yylval.v.string = strdup(buf)) == NULL)
+ err(1, "%s", __func__);
+ return GVAR;
+ } else if (allowed_to_end_number(c) || c == '[') {
+ lungetc();
+ *p = '\0';
+ yylval.v.string = UNNAMED_MAP;
+ return GVAR;
+ }
+ yyerror("'@%s%c' is an invalid variable name", buf, c);
+ return ERROR;
+ break;
case EOF:
return 0;
case '"':
break;
}
-#define allowed_to_end_number(x) \
- (isspace(x) || x == ')' || x == '/' || x == '{' || x == ';' || x == ']' || x == ',')
-
/* parsing number */
if (isdigit(c)) {
do {
}
}
-#define allowed_in_string(x) (isalnum(c) || c == '_')
-
/* parsing next word */
if (allowed_in_string(c)) {
struct keyword *kwp;