From 3cb170588c9b180fb4d28af04e44ac87481560a7 Mon Sep 17 00:00:00 2001 From: jistone Date: Fri, 17 Aug 2007 01:54:28 +0000 Subject: [PATCH] 2007-08-16 Josh Stone 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. --- ChangeLog | 15 ++++++ parse.cxx | 75 ++++++++++++++++++------------ stap.1.in | 47 ++++++++++--------- staptree.cxx | 61 ++++++++++++++++++++---- staptree.h | 7 ++- testsuite/ChangeLog | 13 ++++++ testsuite/buildok/printf.stp | 20 ++++++-- testsuite/lib/stap_run.exp | 2 +- testsuite/parseko/printd01.stp | 6 +++ testsuite/parseko/printd02.stp | 6 +++ testsuite/parseko/printd03.stp | 6 +++ testsuite/parseko/printd04.stp | 6 +++ testsuite/systemtap.base/print.exp | 5 ++ testsuite/systemtap.base/print.stp | 39 ++++++++++++++++ translate.cxx | 11 +++++ 15 files changed, 253 insertions(+), 66 deletions(-) create mode 100644 testsuite/parseko/printd01.stp create mode 100644 testsuite/parseko/printd02.stp create mode 100644 testsuite/parseko/printd03.stp create mode 100644 testsuite/parseko/printd04.stp create mode 100644 testsuite/systemtap.base/print.exp create mode 100644 testsuite/systemtap.base/print.stp diff --git a/ChangeLog b/ChangeLog index a3b60aa19..3f2b53713 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2007-08-16 Josh Stone + + 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 * systemtap.spec.in: Updated %pre to latest Fedora group creation diff --git a/parse.cxx b/parse.cxx index 61d0352af..e22c58ea8 100644 --- 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; diff --git a/stap.1.in b/stap.1.in index 75a408f14..ddd2892f9 100644 --- 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 diff --git a/staptree.cxx b/staptree.cxx index 05d3428bf..10572803d 100644 --- a/staptree.cxx +++ b/staptree.cxx @@ -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 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::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; diff --git a/staptree.h b/staptree.h index 415d510bd..a6b7c1738 100644 --- a/staptree.h +++ b/staptree.h @@ -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 components; + format_component delimiter; std::vector args; hist_op *hist; static std::string components_to_string(std::vector const & components); static std::vector 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); diff --git a/testsuite/ChangeLog b/testsuite/ChangeLog index 7e80f80b6..030848e5b 100644 --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2007-08-16 Josh Stone + + 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 * systemtap.printf/*b.exp: Use stap_merge.tcl. diff --git a/testsuite/buildok/printf.stp b/testsuite/buildok/printf.stp index badea63a0..481892a28 100755 --- a/testsuite/buildok/printf.stp +++ b/testsuite/buildok/printf.stp @@ -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")) } diff --git a/testsuite/lib/stap_run.exp b/testsuite/lib/stap_run.exp index 018d2bf3c..147862182 100644 --- a/testsuite/lib/stap_run.exp +++ b/testsuite/lib/stap_run.exp @@ -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 index 000000000..31eef777d --- /dev/null +++ b/testsuite/parseko/printd01.stp @@ -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 index 000000000..afc7da994 --- /dev/null +++ b/testsuite/parseko/printd02.stp @@ -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 index 000000000..6c6e6a417 --- /dev/null +++ b/testsuite/parseko/printd03.stp @@ -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 index 000000000..5d6aadcb9 --- /dev/null +++ b/testsuite/parseko/printd04.stp @@ -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 index 000000000..9158a2960 --- /dev/null +++ b/testsuite/systemtap.base/print.exp @@ -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 index 000000000..e1b64c357 --- /dev/null +++ b/testsuite/systemtap.base/print.stp @@ -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") +} diff --git a/translate.cxx b/translate.cxx index 54878a400..736e380f5 100644 --- a/translate.cxx +++ b/translate.cxx @@ -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); + } } -- 2.43.5