if (1) {
printf("printed!\n");
}
+
+ if (0)
+ printf("simple if\n");
+ else
+ printf("simple else\n");
+
+ if (0) {
+ printf("disabled if\n");
+ } else if (1) {
+ printf("multiple statements in ");
+ printf("else-if branch\n");
+ } else {
+ printf("no else\n");
+ }
}
END {
printf("(%d) ", @var);
printf("statements\n");
}
+
+ if (0) printf("single-line if\n"); else printf("single-line else\n");
+
+ if (0) {
+ printf("not printed\n");
+ } else {
+ if (0) {
+ printf("nested not printed\n");
+ } else {
+ printf("nested printed\n");
+ exit();
+ printf("nested not printed\n");
+ }
+ printf("also not printed\n");
+ }
}
-/* $OpenBSD: bt_parse.y,v 1.59 2024/02/12 15:11:06 mpi Exp $ */
+/* $OpenBSD: bt_parse.y,v 1.60 2024/03/30 07:41:45 mpi Exp $ */
/*
* Copyright (c) 2019-2023 Martin Pieuchot <mpi@openbsd.org>
%token <v.i> ERROR ENDFILT
%token <v.i> OP_EQ OP_NE OP_LE OP_LT OP_GE OP_GT OP_LAND OP_LOR
/* Builtins */
-%token <v.i> BUILTIN BEGIN END HZ IF STR
+%token <v.i> BUILTIN BEGIN ELSE END HZ IF STR
/* Functions and Map operators */
%token <v.i> F_DELETE F_PRINT
%token <v.i> MFUNC FUNC0 FUNC1 FUNCN OP1 OP2 OP4 MOP0 MOP1
| GVAR '=' OP4 '(' expr ',' vargs ')' { $$ = bh_inc($1, $5, $7); }
;
-stmtblck: IF '(' expr ')' block { $$ = bt_new($3, $5); }
+stmtblck: IF '(' expr ')' block { $$ = bt_new($3, $5, NULL); }
+ | IF '(' expr ')' block ELSE block { $$ = bt_new($3, $5, $7); }
+ | IF '(' expr ')' block ELSE stmtblck { $$ = bt_new($3, $5, $7); }
;
stmtlist: stmtlist stmtblck { $$ = bs_append($1, $2); }
/* Create a new if/else test */
struct bt_stmt *
-bt_new(struct bt_arg *ba, struct bt_stmt *condbs)
+bt_new(struct bt_arg *ba, struct bt_stmt *condbs, struct bt_stmt *elsebs)
{
struct bt_arg *bop;
+ struct bt_cond *bc;
bop = ba_op(B_AT_OP_NE, NULL, ba);
- return bs_new(B_AC_TEST, bop, (struct bt_var *)condbs);
+ bc = calloc(1, sizeof(*bc));
+ if (bc == NULL)
+ err(1, "bt_cond: calloc");
+ bc->bc_condbs = condbs;
+ bc->bc_elsebs = elsebs;
+ return bs_new(B_AC_TEST, bop, (struct bt_var *)bc);
}
+
/* Create a new probe */
struct bt_probe *
bp_new(const char *prov, const char *func, const char *name, int32_t rate)
{ "count", MOP0, B_AT_MF_COUNT },
{ "cpu", BUILTIN, B_AT_BI_CPU },
{ "delete", F_DELETE, B_AC_DELETE },
+ { "else", ELSE, 0 },
{ "exit", FUNC0, B_AC_EXIT },
{ "hist", OP1, 0 },
{ "hz", HZ, 0 },
-/* $OpenBSD: bt_parser.h,v 1.25 2023/10/12 15:16:44 cheloha Exp $ */
+/* $OpenBSD: bt_parser.h,v 1.26 2024/03/30 07:41:45 mpi Exp $ */
/*
* Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org>
#define BA_INITIALIZER(v, t) { { NULL }, (void *)(v), NULL, (t) }
+/*
+ * Represents branches of an if-else statement.
+ */
+struct bt_cond {
+ struct bt_stmt *bc_condbs;
+ struct bt_stmt *bc_elsebs;
+};
+
/*
* Each action associated with a given probe is made of at least one
* statement.
-/* $OpenBSD: btrace.c,v 1.89 2024/02/27 12:38:12 mpi Exp $ */
+/* $OpenBSD: btrace.c,v 1.90 2024/03/30 07:41:45 mpi Exp $ */
/*
* Copyright (c) 2019 - 2023 Martin Pieuchot <mpi@openbsd.org>
rules_action_scan(struct bt_stmt *bs)
{
struct bt_arg *ba;
+ struct bt_cond *bc;
uint64_t evtflags = 0;
while (bs != NULL) {
evtflags |= ba2dtflags(ba);
break;
case B_AC_TEST:
- evtflags |= rules_action_scan(
- (struct bt_stmt *)bs->bs_var);
+ bc = (struct bt_cond *)bs->bs_var;
+ evtflags |= rules_action_scan(bc->bc_condbs);
+ evtflags |= rules_action_scan(bc->bc_elsebs);
break;
default:
break;
}
SLIST_FOREACH(bs, &r->br_action, bs_next) {
- if ((bs->bs_act == B_AC_TEST) && stmt_test(bs, dtev) == true) {
- struct bt_stmt *bbs = (struct bt_stmt *)bs->bs_var;
-
- while (bbs != NULL) {
- if (stmt_eval(bbs, dtev))
- return 1;
- bbs = SLIST_NEXT(bbs, bs_next);
- }
-
- continue;
- }
-
if (stmt_eval(bs, dtev))
return 1;
}
int
stmt_eval(struct bt_stmt *bs, struct dt_evt *dtev)
{
+ struct bt_stmt *bbs;
+ struct bt_cond *bc;
int halt = 0;
switch (bs->bs_act) {
stmt_store(bs, dtev);
break;
case B_AC_TEST:
- /* done before */
+ bc = (struct bt_cond *)bs->bs_var;
+ if (stmt_test(bs, dtev) == true)
+ bbs = bc->bc_condbs;
+ else
+ bbs = bc->bc_elsebs;
+
+ while (bbs != NULL) {
+ if (stmt_eval(bbs, dtev))
+ return 1;
+ bbs = SLIST_NEXT(bbs, bs_next);
+ }
break;
case B_AC_TIME:
stmt_time(bs, dtev);