]> sourceware.org Git - systemtap.git/commitdiff
2007-08-16 Josh Stone <joshua.i.stone@intel.com>
authorjistone <jistone>
Fri, 17 Aug 2007 01:54:28 +0000 (01:54 +0000)
committerjistone <jistone>
Fri, 17 Aug 2007 01:54:28 +0000 (01:54 +0000)
PR 4591
* parse.cxx (parser::parse_symbol): Tweak 'print' matching to allow
all the new variants with printd and println.
* staptree.h (struct print_format): Add fields for the new print
variants, and parse_print() to help matching.
* staptree.cxx (print_format::parse_print): New static method to
match the print variants and determine their properties.
(print_format::print): Handle the new print types.
(deep_copy_visitor::visit_print_format): Copy the new fields.
* translate.cxx (c_unparser::visit_print_format): Insert delims and
newlines where appropriate for new print functions.
* stap1.in: Document the new print functions.

testsuite/
* lib/stap_run.exp: Make sure to match the entire output, in case
there are multiple pass/fail messages.
* buildok/printf.stp: Add lines for new print variants.
* parseko/printd01.stp: Make sure that bad printd calls are handled.
* parseko/printd02.stp: Ditto.
* parseko/printd03.stp: Ditto.
* parseko/printd04.stp: Ditto.
* systemtap.base/print.stp: Try a bunch of different print calls.
* systemtap.base/print.exp: Driver for above.

15 files changed:
ChangeLog
parse.cxx
stap.1.in
staptree.cxx
staptree.h
testsuite/ChangeLog
testsuite/buildok/printf.stp
testsuite/lib/stap_run.exp
testsuite/parseko/printd01.stp [new file with mode: 0644]
testsuite/parseko/printd02.stp [new file with mode: 0644]
testsuite/parseko/printd03.stp [new file with mode: 0644]
testsuite/parseko/printd04.stp [new file with mode: 0644]
testsuite/systemtap.base/print.exp [new file with mode: 0644]
testsuite/systemtap.base/print.stp [new file with mode: 0644]
translate.cxx

index a3b60aa1964111d1256035516478fcd05bb40fe0..3f2b53713cdf2d6a4311c2b6ca648914deecbfb6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2007-08-16  Josh Stone  <joshua.i.stone@intel.com>
+
+       PR 4591
+       * parse.cxx (parser::parse_symbol): Tweak 'print' matching to allow
+       all the new variants with printd and println.
+       * staptree.h (struct print_format): Add fields for the new print
+       variants, and parse_print() to help matching.
+       * staptree.cxx (print_format::parse_print): New static method to
+       match the print variants and determine their properties.
+       (print_format::print): Handle the new print types.
+       (deep_copy_visitor::visit_print_format): Copy the new fields.
+       * translate.cxx (c_unparser::visit_print_format): Insert delims and
+       newlines where appropriate for new print functions.
+       * stap1.in: Document the new print functions.
+
 2007-08-15  David Smith  <dsmith@redhat.com>
 
        * systemtap.spec.in: Updated %pre to latest Fedora group creation
index 61d0352aff550fdd37c77153e080949c92cd334b..e22c58ea80639222340f0b5996788a2d9a7f7591 100644 (file)
--- a/parse.cxx
+++ b/parse.cxx
@@ -2226,6 +2226,8 @@ parser::parse_symbol ()
       // now scrutinize this identifier for the various magic forms of identifier
       // (printf, @stat_op, and $var...)
 
+      bool pf_stream, pf_format, pf_delim, pf_newline;
+
       if (name.size() > 0 && name[0] == '@')
        {
          stat_op *sop = new stat_op;
@@ -2248,36 +2250,19 @@ parser::parse_symbol ()
          return sop;
        }
       
-      else if (name.size() > 0 && (name == "print"
-                                  || name == "sprint"
-                                  || name == "printf"
-                                  || name == "sprintf"))
+      else if (print_format::parse_print(name,
+           pf_stream, pf_format, pf_delim, pf_newline))
        {
          print_format *fmt = new print_format;
          fmt->tok = t;
-         fmt->print_with_format = (name[name.size() - 1] == 'f');
-         fmt->print_to_stream = (name[0] == 'p');
+         fmt->print_to_stream = pf_stream;
+         fmt->print_with_format = pf_format;
+         fmt->print_with_delim = pf_delim;
+         fmt->print_with_newline = pf_newline;
 
          expect_op("(");
-         if (fmt->print_with_format)
-           {
-             // Consume and convert a format string, and any subsequent
-             // arguments. Agreement between the format string and the
-             // arguments is postponed to the typechecking phase. 
-             string tmp;
-             expect_unknown (tok_string, tmp);
-              fmt->raw_components = tmp;
-             fmt->components = print_format::string_to_components (tmp);
-             while (!peek_op (")"))
-               {
-                 expect_op(",");
-                 expression *e = parse_expression ();        
-                 fmt->args.push_back(e);
-               }
-           }
-         else if (name == "print" && 
-                  (peek_kw("@hist_linear") || 
-                   peek_kw("@hist_log")))
+         if (name == "print" &&
+             (peek_kw("@hist_linear") || peek_kw("@hist_log")))
            {
              // We have a special case where we recognize
              // print(@hist_foo(bar)) as a magic print-the-histogram
@@ -2312,10 +2297,42 @@ parser::parse_symbol ()
            }
          else
            {
-             // If we are not printing with a format string, we permit
-             // exactly one argument (of any type).
-             expression *e = parse_expression ();            
-             fmt->args.push_back(e);
+             int min_args = 0;
+             if (fmt->print_with_format)
+               {
+                 // Consume and convert a format string. Agreement between the
+                 // format string and the arguments is postponed to the
+                 // typechecking phase.
+                 string tmp;
+                 expect_unknown (tok_string, tmp);
+                 fmt->raw_components = tmp;
+                 fmt->components = print_format::string_to_components (tmp);
+               }
+             else if (fmt->print_with_delim)
+               {
+                 // Consume a delimiter to separate arguments.
+                 fmt->delimiter.clear();
+                 fmt->delimiter.type = print_format::conv_literal;
+                 expect_unknown (tok_string, fmt->delimiter.literal_string);
+                 min_args = 2;
+               }
+             else
+               {
+                 // If we are not printing with a format string, we must have
+                 // at least one argument (of any type).
+                 expression *e = parse_expression ();
+                 fmt->args.push_back(e);
+               }
+
+             // Consume any subsequent arguments.
+             while (min_args || !peek_op (")"))
+               {
+                 expect_op(",");
+                 expression *e = parse_expression ();
+                 fmt->args.push_back(e);
+                 if (min_args)
+                   --min_args;
+               }
            }
          expect_op(")");
          return fmt;
index 75a408f14fcdbfe9b46ab65db21c484083027735..ddd2892f96916845cc06083647e798cd599a2d6e 100644 (file)
--- a/stap.1.in
+++ b/stap.1.in
@@ -512,31 +512,32 @@ recursively, up to a fixed nesting limit.  This limit is defined by
 a macro in the translated C code and is in the neighbourhood of 10.
 
 .SS PRINTING
-The function names
-.IR print ", " printf ", " sprint ", and " sprintf
-are specially treated by the translator.  They format values for
-printing to the standard systemtap log stream in a more convenient
-way.
-.PP
+There are a set of function names that are specially treated by the
+translator.  They format values for printing to the standard systemtap
+log stream in a more convenient way.  The
+.IR sprint*
+variants return the formatted string instead of logging it.
+.TP
+.BR print ", " sprint
+Print one or more values of any type, concatenated directly together.
 .TP
-print
-takes a single value of any type, and prints it
+.BR println ", " sprintln
+Print values like
+.IR print " and " sprint ,
+but also append a newline.
 .TP
-sprint
-operates like
-.IR print ,
-but returns the formatted string instead of logging it.
+.BR printd ", " sprintd
+Take a string delimiter and two or more values of any type, and print the
+values with the delimiter interposed.
 .TP
-printf
-takes a formatting string, and a number of values of corresponding types,
-and prints them all.
+.BR printdln ", " sprintdln
+Print values with a delimiter like
+.IR printd " and " sprintd ,
+but also append a newline.
 .TP
-sprintf
-operates like
-.IR printf ,
-but like
-.IR sprint ,
-returns the formatted string instead of logging it.
+.BR printf ", " sprintf
+Take a formatting string and a number of values of corresponding types,
+and print them all.
 .PP
 The
 .IR printf
@@ -555,6 +556,10 @@ fully type-checked by the translator.
                sprintf("%s before %s", 
                        sprint(1), sprint(3)), 
                sprint("C"))
+       id[bob] = 1234
+       id[alice] = 5678
+       foreach (name in id)
+               printdln("|", strlen(name), name, id[name])
 .ESAMPLE
 
 .SS STATISTICS
index 05d3428bfde9a6c8e8e888faf9febb6bf68ae3ac..10572803d91ebf2b4ca3e0dc3545c973d42ad8ab 100644 (file)
@@ -338,6 +338,49 @@ void functioncall::print (ostream& o) const
 }  
 
 
+bool
+print_format::parse_print(const std::string &name,
+    bool &stream, bool &format, bool &delim, bool &newline)
+{
+  const char *n = name.c_str();
+
+  stream = true;
+  format = delim = newline = false;
+
+  if (*n == 's')
+    {
+      stream = false;
+      ++n;
+    }
+
+  if (0 != strncmp(n, "print", 5))
+    return false;
+  n += 5;
+
+  if (*n == 'f')
+    {
+      format = true;
+      ++n;
+    }
+  else
+    {
+      if (*n == 'd')
+        {
+         delim = true;
+         ++n;
+       }
+
+      if (*n == 'l' && *(n+1) == 'n')
+        {
+         newline = true;
+         n += 2;
+       }
+    }
+
+  return (*n == '\0');
+}
+
+
 string 
 print_format::components_to_string(vector<format_component> const & components)
 {
@@ -611,20 +654,17 @@ print_format::string_to_components(string const & str)
 
 void print_format::print (ostream& o) const
 {
-  string name = (string(print_to_stream ? "" : "s") 
-                + string("print") 
-                + string(print_with_format ? "f" : ""));
-  o << name << "(";
+  o << tok->content << "(";
   if (print_with_format)
-    {
-      o << lex_cast_qstring (raw_components);
-    }
+    o << lex_cast_qstring (raw_components);
+  if (print_with_delim)
+    o << lex_cast_qstring (delimiter.literal_string);
   if (hist)
     hist->print(o);
   for (vector<expression*>::const_iterator i = args.begin();
        i != args.end(); ++i)
     {
-      if (i != args.begin() || print_with_format)
+      if (i != args.begin() || print_with_format || print_with_delim)
        o << ", ";
       (*i)->print(o);
     }
@@ -2252,10 +2292,13 @@ deep_copy_visitor::visit_print_format (print_format* e)
 {
   print_format* n = new print_format;
   n->tok = e->tok;
-  n->print_with_format = e->print_with_format;
   n->print_to_stream = e->print_to_stream;
+  n->print_with_format = e->print_with_format;
+  n->print_with_delim = e->print_with_delim;
+  n->print_with_newline = e->print_with_newline;
   n->raw_components = e->raw_components;
   n->components = e->components;
+  n->delimiter = e->delimiter;
   for (unsigned i = 0; i < e->args.size(); ++i)
     {
       expression* na;
index 415d510bda7e397c3e0b6a71c8446d74b38cabb6..a6b7c1738589888dfacc215cf8b5ec848211e4b1 100644 (file)
@@ -262,8 +262,10 @@ struct functioncall: public expression
 
 struct print_format: public expression
 {
-  bool print_with_format;
   bool print_to_stream;
+  bool print_with_format;
+  bool print_with_delim;
+  bool print_with_newline;
 
   enum format_flag
     {
@@ -320,11 +322,14 @@ struct print_format: public expression
 
   std::string raw_components;
   std::vector<format_component> components;
+  format_component delimiter;
   std::vector<expression*> args;
   hist_op *hist;
 
   static std::string components_to_string(std::vector<format_component> const & components);
   static std::vector<format_component> string_to_components(std::string const & str);
+  static bool parse_print(const std::string &name,
+      bool &stream, bool &format, bool &delim, bool &newline);
 
   void print (std::ostream& o) const;
   void visit (visitor* u);
index 7e80f80b688a10e9f93cb649ba0d3710d8c3bc3f..030848e5b3a18fa0be540d367a0aa48d57ed7a54 100644 (file)
@@ -1,3 +1,16 @@
+2007-08-16  Josh Stone  <joshua.i.stone@intel.com>
+
+       PR 4591
+       * lib/stap_run.exp: Make sure to match the entire output, in case
+       there are multiple pass/fail messages.
+       * buildok/printf.stp: Add lines for new print variants.
+       * parseko/printd01.stp: Make sure that bad printd calls are handled.
+       * parseko/printd02.stp: Ditto.
+       * parseko/printd03.stp: Ditto.
+       * parseko/printd04.stp: Ditto.
+       * systemtap.base/print.stp: Try a bunch of different print calls.
+       * systemtap.base/print.exp: Driver for above.
+
 2007-08-15  Martin Hunt  <hunt@redhat.com>
 
        * systemtap.printf/*b.exp: Use stap_merge.tcl.
index badea63a0c6f3e0f615c13b7e4a079258ec0920f..481892a28bbfc548c4d50267c47e46b4b44b74b0 100755 (executable)
@@ -26,9 +26,19 @@ probe begin
                sprintf("%s before %s", 
                        sprint(1), sprint(3)), 
                sprint("C"))
-        printf("\"quote\\this\"\n")
-        printf("%d is %03o in octal\n", 9, 9)
-        printf("%d is %#X in hex\n", 255, 255)
-        printf("print unsigned %u\n", 17)
-        printf("-% d is % d\n", 9, -9)
+       printf("\"quote\\this\"\n")
+       printf("%d is %03o in octal\n", 9, 9)
+       printf("%d is %#X in hex\n", 255, 255)
+       printf("print unsigned %u\n", 17)
+       printf("-% d is % d\n", 9, -9)
+
+       print(1, "two", 3, "four")
+       print(sprint(1, "two", 3, "four"))
+       println(1, "two", 3, "four")
+       print(sprintln(1, "two", 3, "four"))
+
+       printd(", ", 1, "two", 3, "four")
+       print(sprintd(", ", 1, "two", 3, "four"))
+       printdln(", ", 1, "two", 3, "four")
+       print(sprintdln(", ", 1, "two", 3, "four"))
 }
index 018d2bf3c1e22e2097923e620e1313ca01f420d5..14786218225c5543f8cd77343e303cdf785c7f09 100644 (file)
@@ -86,4 +86,4 @@ proc no_load {} {
 }
 
 # tests better all be true
-set all_pass_string "(systemtap test success\r\n)+"
+set all_pass_string "(systemtap test success\r\n)+$"
diff --git a/testsuite/parseko/printd01.stp b/testsuite/parseko/printd01.stp
new file mode 100644 (file)
index 0000000..31eef77
--- /dev/null
@@ -0,0 +1,6 @@
+#! stap -p1
+
+probe begin {
+    // missing the delimiter
+    printd(1, 2, 3, 4, 5)
+}
diff --git a/testsuite/parseko/printd02.stp b/testsuite/parseko/printd02.stp
new file mode 100644 (file)
index 0000000..afc7da9
--- /dev/null
@@ -0,0 +1,6 @@
+#! stap -p1
+
+probe begin {
+    // missing the delimiter
+    printdln(1, 2, 3, 4, 5)
+}
diff --git a/testsuite/parseko/printd03.stp b/testsuite/parseko/printd03.stp
new file mode 100644 (file)
index 0000000..6c6e6a4
--- /dev/null
@@ -0,0 +1,6 @@
+#! stap -p1
+
+probe begin {
+    // need more than one value to join
+    printd(", ", 1)
+}
diff --git a/testsuite/parseko/printd04.stp b/testsuite/parseko/printd04.stp
new file mode 100644 (file)
index 0000000..5d6aadc
--- /dev/null
@@ -0,0 +1,6 @@
+#! stap -p1
+
+probe begin {
+    // need more than one value to join
+    printdln(", ", 1)
+}
diff --git a/testsuite/systemtap.base/print.exp b/testsuite/systemtap.base/print.exp
new file mode 100644 (file)
index 0000000..9158a29
--- /dev/null
@@ -0,0 +1,5 @@
+# Test that all the print statements work
+
+set test "print"
+
+stap_run $srcdir/$subdir/$test.stp no_load $all_pass_string
diff --git a/testsuite/systemtap.base/print.stp b/testsuite/systemtap.base/print.stp
new file mode 100644 (file)
index 0000000..e1b64c3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * print.stp
+ *
+ * Test that all the print statements work
+ */
+
+global s1, s2, s3
+
+probe begin
+{
+       log("systemtap starting probe")
+    s1 = "systemtap"
+    s2 = "test"
+    s3 = "success"
+}
+
+probe end
+{
+       log("systemtap ending probe")
+
+    print(s1, " ", s2, " ", s3, "\n")
+    print(sprint(s1, " ", s2, " ", s3, "\n"))
+
+    println(s1, " ", s2, " ", s3)
+    print(sprintln(s1, " ", s2, " ", s3))
+
+    printd(" ", s1, s2, s3 . "\n")
+    print(sprintd(" ", s1, s2, s3 . "\n"))
+
+    printdln(" ", s1, s2, s3)
+    print(sprintdln(" ", s1, s2, s3))
+
+    // check that formatting characters get escaped correctly in the delimiter
+    s = sprintd("%% % \\ \"", 1, 2, 3)
+    if (s == "1%% % \\ \"2%% % \\ \"3")
+        log("systemtap test success")
+    else
+        log("systemtap test failure")
+}
index 54878a4006e80919c6393f3c6e35b2d0599c8752..736e380f5d5ec0f362756266404b38002a6ebe5d 100644 (file)
@@ -4010,6 +4010,8 @@ c_unparser::visit_print_format (print_format* e)
          // directive for each argument.
          for (unsigned i = 0; i < e->args.size(); ++i)
            {
+             if (i > 0 && e->print_with_delim)
+               components.push_back (e->delimiter);
              print_format::format_component curr;
              curr.clear();
              switch (e->args[i]->type)
@@ -4027,6 +4029,15 @@ c_unparser::visit_print_format (print_format* e)
                }
              components.push_back (curr);
            }
+
+         if (e->print_with_newline)
+           {
+             print_format::format_component curr;
+             curr.clear();
+             curr.type = print_format::conv_literal;
+             curr.literal_string = "\\n";
+             components.push_back (curr);
+           }
        }
 
 
This page took 0.053628 seconds and 5 git commands to generate.