Implement else branching logic including 'else if'.
authormpi <mpi@openbsd.org>
Sat, 30 Mar 2024 07:41:45 +0000 (07:41 +0000)
committermpi <mpi@openbsd.org>
Sat, 30 Mar 2024 07:41:45 +0000 (07:41 +0000)
Statement lists for if & else conditions are now wrapped in a new
'struct bt_cond'.  Handling B_AC_TEST statements moved to stmt_eval()
to handle nested conditional statements.

From Christian Ludwig christian_ludwig at genua.de

regress/usr.sbin/btrace/if.bt
regress/usr.sbin/btrace/if.ok
usr.sbin/btrace/bt_parse.y
usr.sbin/btrace/bt_parser.h
usr.sbin/btrace/btrace.c

index 053801c..41f3081 100644 (file)
@@ -9,6 +9,20 @@ BEGIN {
        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 {
@@ -18,4 +32,19 @@ 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");
+       }
 }
index c2d5a91..cfac256 100644 (file)
@@ -1,2 +1,6 @@
 printed!
+simple else
+multiple statements in else-if branch
 multiple (4) statements
+single-line else
+nested printed
index 075eaa5..2497ae4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -119,7 +119,7 @@ static int   beflag = 0;            /* BEGIN/END parsing context flag */
 %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
@@ -248,7 +248,9 @@ stmt        : ';' NL                        { $$ = NULL; }
        | 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); }
@@ -340,15 +342,22 @@ bc_new(struct bt_arg *term, enum bt_argtype op, struct bt_arg *ba)
 
 /* 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)
@@ -714,6 +723,7 @@ lookup(char *s)
                { "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 },
index 051bd72..081c004 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -180,6 +180,14 @@ struct bt_arg {
 
 #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.
index ce32989..b817d9c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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>
@@ -460,6 +460,7 @@ static uint64_t
 rules_action_scan(struct bt_stmt *bs)
 {
        struct bt_arg *ba;
+       struct bt_cond *bc;
        uint64_t evtflags = 0;
 
        while (bs != NULL) {
@@ -474,8 +475,9 @@ rules_action_scan(struct bt_stmt *bs)
                        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;
@@ -669,18 +671,6 @@ rule_eval(struct bt_rule *r, struct dt_evt *dtev)
        }
 
        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;
        }
@@ -830,6 +820,8 @@ builtin_arg(struct dt_evt *dtev, enum bt_argtype dat)
 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) {
@@ -858,7 +850,17 @@ stmt_eval(struct bt_stmt *bs, struct dt_evt *dtev)
                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);