This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Make the 3rd operand of ternary '?:' bind tighter than binary '='


In the C language, the 3rd operand of the ternary operator binds tighter
than the binary assignment operators. It is better for the stap language
to be consistent with C in operator precedence.

Added several tests to check the precedence of the ternary operator.
I've verified the results with similar C programs with gcc myself.
---
 parse.cxx                                 |   2 +-
 testsuite/systemtap.base/ternary_op.exp   | 135 ++++++++++++++++++++++++++++++
 testsuite/systemtap.base/ternary_op_1.stp |   5 ++
 testsuite/systemtap.base/ternary_op_2.stp |   5 ++
 testsuite/systemtap.base/ternary_op_3.stp |   5 ++
 5 files changed, 151 insertions(+), 1 deletion(-)
 create mode 100644 testsuite/systemtap.base/ternary_op.exp
 create mode 100644 testsuite/systemtap.base/ternary_op_1.stp
 create mode 100644 testsuite/systemtap.base/ternary_op_2.stp
 create mode 100644 testsuite/systemtap.base/ternary_op_3.stp

diff --git a/parse.cxx b/parse.cxx
index 751f56add..169486d8d 100644
--- a/parse.cxx
+++ b/parse.cxx
@@ -3286,7 +3286,7 @@ parser::parse_ternary ()
         throw PARSE_ERROR (_("expected ':'"));
       swallow ();
 
-      e->falsevalue = parse_expression (); // XXX
+      e->falsevalue = parse_ternary (); // XXX
       return e;
     }
   else
diff --git a/testsuite/systemtap.base/ternary_op.exp b/testsuite/systemtap.base/ternary_op.exp
new file mode 100644
index 000000000..4f9eabf21
--- /dev/null
+++ b/testsuite/systemtap.base/ternary_op.exp
@@ -0,0 +1,135 @@
+set test "ternary_op"
+set testpath "$srcdir/$subdir"
+
+if {! [installtest_p]} { untested "$test"; return }
+
+# --- TEST 1 ---
+
+set subtest1 "TEST 1: ternary operator should be tighter than ,"
+foreach runtime [get_runtime_list] {
+    if {$runtime eq ""} {
+        set runtime "kernel"
+    }
+    set test_name "$test: $subtest1 ($runtime)"
+
+    set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_1.stp'"
+    send_log "executing: $cmd\n"
+    set pipe [open "| sh -c {$cmd}" r]
+    set out [read $pipe]
+    set failed 0
+    if {[catch {close $pipe} stderr] != 0} {
+        if {$stderr ne "" && [string index $stderr end] ne "\n"} {
+            append stderr "\n"
+        }
+        global errorCode
+        if {"CHILDSTATUS" == [lindex $errorCode 0]} {
+            set failed [lindex $errorCode 2]
+        }
+    }
+
+    set exp_out "positive 3\n"
+    regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+    if {$out eq $exp_out} {
+        pass "${test_name}: stdout matches \"$escaped_exp_out\""
+    } else {
+        fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+    }
+
+    if {$failed} {
+        fail "${test_name}: exit code should be zero but is $failed"
+    } else {
+        pass "${test_name}: exit code is zero"
+    }
+    if {$stderr ne ""} {
+        send_log "stderr:\n$stderr"
+    }
+}
+
+# --- TEST 2 ---
+
+set subtest2 "TEST 2: ternary operator should be tighter than = (bad case)"
+set test_name "$test: $subtest2"
+
+set cmd "stap '$srcdir/$subdir/${test}_2.stp'"
+send_log "executing: $cmd\n"
+set pipe [open "| sh -c {$cmd}" r]
+set out [read $pipe]
+set failed 0
+if {[catch {close $pipe} stderr] != 0} {
+    if {$stderr ne "" && [string index $stderr end] ne "\n"} {
+        append stderr "\n"
+    }
+    global errorCode
+    if {"CHILDSTATUS" == [lindex $errorCode 0]} {
+        set failed [lindex $errorCode 2]
+    }
+}
+
+set exp_out ""
+regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+if {$out eq $exp_out} {
+    pass "${test_name}: stdout matches \"$escaped_exp_out\""
+} else {
+    fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+}
+
+if {$failed} {
+    pass "${test_name}: exit code should be non-zero"
+} else {
+    fail "${test_name}: exit code should be non-zero but is zero"
+}
+
+set stderr_pat "^semantic error: Expecting lvalue for assignment: operator '=' at :3:38\\n        source:     printf\\(\"%d\\\\n\", a > 0 \\? b = 3 : c = 4\\);\\n                                                     \\^\\n"
+regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+if {[regexp -linestop -lineanchor -- $stderr_pat $stderr]} {
+    pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+} else {
+    fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+}
+
+# --- TEST 3 ---
+
+set subtest3 "TEST 3: ternary operator should be tighter than = (good case, with parens)"
+foreach runtime [get_runtime_list] {
+    if {$runtime eq ""} {
+        set runtime "kernel"
+    }
+    set test_name "$test: $subtest3 ($runtime)"
+
+    set cmd "stap --runtime=$runtime '$srcdir/$subdir/${test}_3.stp'"
+    send_log "executing: $cmd\n"
+    set pipe [open "| sh -c {$cmd}" r]
+    set out [read $pipe]
+    set failed 0
+    if {[catch {close $pipe} stderr] != 0} {
+        if {$stderr ne "" && [string index $stderr end] ne "\n"} {
+            append stderr "\n"
+        }
+        global errorCode
+        if {"CHILDSTATUS" == [lindex $errorCode 0]} {
+            set failed [lindex $errorCode 2]
+        }
+    }
+
+    set exp_out "3\n"
+    regsub -all -- {\n} $exp_out {\n} escaped_exp_out
+    if {$out eq $exp_out} {
+        pass "${test_name}: stdout matches \"$escaped_exp_out\""
+    } else {
+        fail "${test_name}: stdout fails to match \"$escaped_exp_out\": got \"$out\""
+    }
+
+    set stderr_pat "^WARNING: Eliding assignment to 'b': operator '=' at \[^\\n\]*?\\.stp:3:30\n.*?\nWARNING: Eliding assignment to 'c': operator '=' at :3:39\n"
+    regsub -all -- {\n} $stderr_pat {\n} escaped_stderr_pat
+    if {[regexp -lineanchor -- $stderr_pat $stderr]} {
+        pass "${test_name}: stderr matches \"$escaped_stderr_pat\""
+    } else {
+        fail "${test_name}: stderr fails to match \"$escaped_stderr_pat\": got \"$stderr\""
+    }
+
+    if {$failed} {
+        fail "${test_name}: exit code should be zero but is $failed"
+    } else {
+        pass "${test_name}: exit code is zero"
+    }
+}
diff --git a/testsuite/systemtap.base/ternary_op_1.stp b/testsuite/systemtap.base/ternary_op_1.stp
new file mode 100644
index 000000000..d4be95987
--- /dev/null
+++ b/testsuite/systemtap.base/ternary_op_1.stp
@@ -0,0 +1,5 @@
+probe begin {
+    a = 3;
+    printf("%s %d\n", a > 0 ? "positive" : "negative", a);
+    exit();
+}
diff --git a/testsuite/systemtap.base/ternary_op_2.stp b/testsuite/systemtap.base/ternary_op_2.stp
new file mode 100644
index 000000000..ca4426812
--- /dev/null
+++ b/testsuite/systemtap.base/ternary_op_2.stp
@@ -0,0 +1,5 @@
+probe begin {
+    a = 3;
+    printf("%d\n", a > 0 ? b = 3 : c = 4);
+    exit();
+}
diff --git a/testsuite/systemtap.base/ternary_op_3.stp b/testsuite/systemtap.base/ternary_op_3.stp
new file mode 100644
index 000000000..8e6593b28
--- /dev/null
+++ b/testsuite/systemtap.base/ternary_op_3.stp
@@ -0,0 +1,5 @@
+probe begin {
+    a = 3;
+    printf("%d\n", a > 0 ? b = 3 : (c = 4));
+    exit();
+}
-- 
2.11.0.295.gd7dffce


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]