From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 15839 invoked by alias); 4 Apr 2007 14:48:36 -0000 Received: (qmail 15830 invoked by uid 22791); 4 Apr 2007 14:48:34 -0000 X-Spam-Status: No, hits=-0.6 required=5.0 tests=AWL,BAYES_50,DNS_FROM_RFC_ABUSE,TW_DX,TW_RV,TW_TR X-Spam-Check-By: sourceware.org Received: from ecfrec.frec.bull.fr (HELO ecfrec.frec.bull.fr) (129.183.4.8) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 04 Apr 2007 15:48:24 +0100 Received: from localhost (localhost [127.0.0.1]) by ecfrec.frec.bull.fr (Postfix) with ESMTP id 9B39419D951 for ; Wed, 4 Apr 2007 16:48:16 +0200 (CEST) Received: from ecfrec.frec.bull.fr ([127.0.0.1]) by localhost (ecfrec.frec.bull.fr [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 05731-01 for ; Wed, 4 Apr 2007 16:48:13 +0200 (CEST) Received: from ecn002.frec.bull.fr (ecn002.frec.bull.fr [129.183.4.6]) by ecfrec.frec.bull.fr (Postfix) with ESMTP id 4191B19D958 for ; Wed, 4 Apr 2007 16:48:12 +0200 (CEST) Received: from [129.183.140.92] ([129.183.140.92]) by ecn002.frec.bull.fr (Lotus Domino Release 5.0.12) with ESMTP id 2007040416503696:52864 ; Wed, 4 Apr 2007 16:50:36 +0200 Message-ID: <4613BA5A.6020104@bull.net> Date: Wed, 04 Apr 2007 14:48:00 -0000 From: Pierre Peiffer User-Agent: Thunderbird 1.5.0.10 (X11/20070302) MIME-Version: 1.0 To: systemtap@sourceware.org Subject: Patch: allow use of $x and @x References: <461266B2.6040009@bull.net> <46126835.9080709@bull.net> <46126E31.6090209@bull.net> <4613505A.4030108@bull.net> In-Reply-To: <4613505A.4030108@bull.net> X-MIMETrack: Itemize by SMTP Server on ECN002/FR/BULL(Release 5.0.12 |February 13, 2003) at 04/04/2007 16:50:37, Serialize by Router on ECN002/FR/BULL(Release 5.0.12 |February 13, 2003) at 04/04/2007 16:50:39, Serialize complete at 04/04/2007 16:50:39 Content-Type: multipart/mixed; boundary="------------080207050307060304030407" X-Virus-Scanned: by amavisd-new at frec.bull.fr X-Virus-Checked: Checked by ClamAV on sourceware.org X-IsSubscribed: yes Mailing-List: contact systemtap-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: systemtap-owner@sourceware.org X-SW-Source: 2007-q2/txt/msg00019.txt.bz2 This is a multi-part message in MIME format. --------------080207050307060304030407 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-length: 1229 Ok, here is a patch including everything (hopefully) about the use of $# and @# to access the number of argument.. I've merged the two patches into one. I have updated and added some tests in the testsuite to test these new identifiers. And I also have (tried to) updated the man. Also there is some minor changes/updates to improve my previous code. Here is a detailled changelog: * parse.cxx, parse.h: Add $# and @# identifiers to access the number of arguments. - Allow the use of $x and @x identifiers during the preprocessing. - Produce more accurate error message when having incomplete conditional during the preprocessing. * stap.1.in: Document $# and @# identifiers. And in the testsuite: * parseok/fourteen.stp: Add test about $# and @# usage during the preprocessing. * parseko/preprocess10.stp: New test. * parseko/preprocess11.stp: New test. * parseko/preprocess12.stp: New test. Thanks, Pierre Peiffer a écrit : > Frank Ch. Eigler a écrit : > >> >> The ideas and patches look fine. They would need to be completed by >> the addition of some documentation to the man pages, and some bits for >> the testsuite. Would you like to do that too? >> > Yep, I'll try to do that today. > -- Pierre --------------080207050307060304030407 Content-Transfer-Encoding: 7bit Content-Type: text/x-patch; name="allow-number-of-args-pattern.patch" Content-Disposition: inline; filename="allow-number-of-args-pattern.patch" Content-length: 14012 --- ChangeLog | 9 ++ parse.cxx | 128 +++++++++++++++++++++++++++---------- parse.h | 5 - stap.1.in | 23 ++++-- testsuite/ChangeLog | 8 ++ testsuite/parseko/preprocess10.stp | 4 + testsuite/parseko/preprocess11.stp | 4 + testsuite/parseko/preprocess12.stp | 5 + testsuite/parseok/fourteen.stp | 11 +++ 9 files changed, 157 insertions(+), 40 deletions(-) Index: b/parse.cxx =================================================================== --- a/parse.cxx +++ b/parse.cxx @@ -1,6 +1,7 @@ // recursive descent parser for systemtap scripts // Copyright (C) 2005-2007 Red Hat Inc. // Copyright (C) 2006 Intel Corporation. +// Copyright (C) 2007 Bull S.A.S // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -146,6 +147,8 @@ parser::last () // The basic form is %( CONDITION %? THEN-TOKENS %: ELSE-TOKENS %) // where CONDITION is: kernel_v[r] COMPARISON-OP "version-string" // or: arch COMPARISON-OP "arch-string" +// or: "string1" COMPARISON-OP "string2" +// or: number1 COMPARISON-OP number2 // The %: ELSE-TOKENS part is optional. // // e.g. %( kernel_v > "2.5" %? "foo" %: "baz" %) @@ -212,14 +215,51 @@ bool eval_pp_conditional (systemtap_sess return result; } + else if ((l->type == tok_string && r->type == tok_string) + || (l->type == tok_number && r->type == tok_number)) + { + // collect acceptable strverscmp results. + int rvc_ok1, rvc_ok2; + if (op->type == tok_operator && op->content == "<=") + { rvc_ok1 = -1; rvc_ok2 = 0; } + else if (op->type == tok_operator && op->content == ">=") + { rvc_ok1 = 1; rvc_ok2 = 0; } + else if (op->type == tok_operator && op->content == "<") + { rvc_ok1 = -1; rvc_ok2 = -1; } + else if (op->type == tok_operator && op->content == ">") + { rvc_ok1 = 1; rvc_ok2 = 1; } + else if (op->type == tok_operator && op->content == "==") + { rvc_ok1 = 0; rvc_ok2 = 0; } + else if (op->type == tok_operator && op->content == "!=") + { rvc_ok1 = -1; rvc_ok2 = 1; } + else + throw parse_error ("expected comparison operator", op); + + int rvc_result = l->content.compare(r->content); + + // normalize rvc_result + if (rvc_result < 0) rvc_result = -1; + if (rvc_result > 0) rvc_result = 1; + + return (rvc_result == rvc_ok1 || rvc_result == rvc_ok2); + } + else if (l->type == tok_string && r->type == tok_number + && op->type == tok_operator) + throw parse_error ("expected string literal as right value", r); + else if (l->type == tok_number && r->type == tok_string + && op->type == tok_operator) + throw parse_error ("expected number literal as right value", r); // XXX: support other forms? "CONFIG_SMP" ? else - throw parse_error ("expected 'arch' or 'kernel_v' or 'kernel_vr'", l); + throw parse_error ("expected 'arch' or 'kernel_v' or 'kernel_vr'\n" + " or comparison between strings or integers", l); } +// expand_args is used to know if we must expand $x and @x identifiers. +// Only tokens corresponding to the TRUE statement must be expanded const token* -parser::scan_pp () +parser::scan_pp (bool expand_args) { while (true) { @@ -230,7 +270,7 @@ parser::scan_pp () return t; } - const token* t = input.scan (); // NB: not recursive! + const token* t = input.scan (expand_args); // NB: not recursive! if (t == 0) // EOF return t; @@ -240,15 +280,17 @@ parser::scan_pp () // We have a %( - it's time to throw a preprocessing party! const token *l, *op, *r; - l = input.scan (); // NB: not recursive, though perhaps could be - op = input.scan (); - r = input.scan (); + l = input.scan (expand_args); // NB: not recursive, though perhaps could be + op = input.scan (expand_args); + r = input.scan (expand_args); if (l == 0 || op == 0 || r == 0) throw parse_error ("incomplete condition after '%('", t); // NB: consider generalizing to consume all tokens until %?, and // passing that as a vector to an evaluator. - bool result = eval_pp_conditional (session, l, op, r); + // Do not evaluate the condition if we haven't expanded everything. + // This may occured when having several recursive conditionals. + bool result = expand_args && eval_pp_conditional (session, l, op, r); delete l; delete op; delete r; @@ -259,13 +301,18 @@ parser::scan_pp () delete m; // "%?" vector my_enqueued_pp; + bool have_token = false; while (true) // consume THEN tokens { - m = scan_pp (); // NB: recursive + m = scan_pp (result); // NB: recursive if (m == 0) - throw parse_error ("missing THEN tokens for conditional", t); - + if (have_token) + throw parse_error ("incomplete conditional - missing %: or %)", t); + else + throw parse_error ("missing THEN tokens for conditional", t); + + have_token = true; if (m->type == tok_operator && (m->content == "%:" || // ELSE m->content == "%)")) // END break; @@ -277,15 +324,20 @@ parser::scan_pp () // continue } + have_token = false; if (m && m->type == tok_operator && m->content == "%:") // ELSE { delete m; // "%:" while (true) { - m = scan_pp (); // NB: recursive + m = scan_pp (expand_args && !result); // NB: recursive if (m == 0) - throw parse_error ("missing ELSE tokens for conditional", t); + if (have_token) + throw parse_error ("incomplete conditional - missing %)", t); + else + throw parse_error ("missing ELSE tokens for conditional", t); + have_token = true; if (m->type == tok_operator && m->content == "%)") // END break; // enqueue token @@ -473,7 +525,7 @@ lexer::input_get () token* -lexer::scan () +lexer::scan (bool expand_args) { token* n = new token; n->location.file = input_name; @@ -501,7 +553,7 @@ lexer::scan () int c2 = input_peek (); if (! input) break; - if ((isalnum(c2) || c2 == '_' || c2 == '$')) + if ((isalnum(c2) || c2 == '_' || c2 == '$' || c2 == '#' )) { n->content.push_back(c2); input_get (); @@ -514,24 +566,36 @@ lexer::scan () // numbers and @1 .. @999 as strings. if (n->content[0] == '@' || n->content[0] == '$') { - string idxstr = n->content.substr(1); - const char* startp = idxstr.c_str(); - char *endp; - errno = 0; - unsigned long idx = strtoul (startp, &endp, 10); - if (endp == startp) - ; // no numbers at all - leave alone as identifier - else - { - // Use @1/$1 as the base, not @0/$0. Thus the idx-1. - if (errno == ERANGE || errno == EINVAL || *endp != '\0' || - idx == 0 || idx-1 >= session.args.size ()) - throw parse_error ("command line argument index invalid or out of range", n); - - string arg = session.args[idx-1]; - n->type = (n->content[0] == '@') ? tok_string : tok_number; - n->content = arg; - } + if (!expand_args) + return n; + if (n->content[1] == '#') + { + stringstream converter; + converter << session.args.size (); + n->type = (n->content[0] == '@') ? tok_string : tok_number; + n->content = converter.str(); + } + else + { + string idxstr = n->content.substr(1); + const char* startp = idxstr.c_str(); + char *endp; + errno = 0; + unsigned long idx = strtoul (startp, &endp, 10); + if (endp == startp) + ; // no numbers at all - leave alone as identifier + else + { + // Use @1/$1 as the base, not @0/$0. Thus the idx-1. + if (errno == ERANGE || errno == EINVAL || *endp != '\0' || + idx == 0 || idx-1 >= session.args.size ()) + throw parse_error ("command line argument index invalid or out of range", n); + + string arg = session.args[idx-1]; + n->type = (n->content[0] == '@') ? tok_string : tok_number; + n->content = arg; + } + } } else { Index: b/ChangeLog =================================================================== --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2007-04-03 Pierre Peiffer + + * parse.cxx, parse.h: Add $# and @# identifiers to access the number + of arguments. + - Allow the use of $x and @x identifiers during the preprocessing. + - Produce more accurate error message when having incomplete + conditional during the preprocessing. + * stap.1.in: Document $# and @# identifiers. + 2007-03-22 Frank Ch. Eigler PR 4224. Index: b/parse.h =================================================================== --- a/parse.h +++ b/parse.h @@ -1,5 +1,6 @@ // -*- C++ -*- // Copyright (C) 2005 Red Hat Inc. +// Copyright (C) 2007 Bull S.A.S // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General @@ -64,7 +65,7 @@ struct systemtap_session; class lexer { public: - token* scan (); + token* scan (bool expand_args=true); lexer (std::istream&, const std::string&, systemtap_session&); private: @@ -124,7 +125,7 @@ private: // preprocessing subordinate std::vector enqueued_pp; - const token* scan_pp (); + const token* scan_pp (bool expand_args=true); // scanning state const token* last (); Index: b/stap.1.in =================================================================== --- a/stap.1.in +++ b/stap.1.in @@ -185,10 +185,16 @@ be expanded as literals. Use .B $1 ... $ for casting as a numeric literal and .B @1 ... @ -for casting as string literal. These may be used in all contexts -where literals are accepted. Reference to an argument number beyond -what was actually given is an error. -.PP +for casting as string literal. The number of arguments may be accessed +through +.B $# +(as a numeric literal) or through +.B @# +(as a string literal). These may be used in all contexts where literals +are accepted, including preprocessing stage. Reference to an argument +number beyond what was actually given is an error. + +.SS PREPROCESSING A simple conditional preprocessing stage is run as a part of parsing. The general form is similar to the .RB cond " ? " exp1 " : " exp2 @@ -197,8 +203,9 @@ ternary operator: .BR %( " CONDITION " %? " TRUE-TOKENS " %) .BR %( " CONDITION " %? " TRUE-TOKENS " %: " FALSE-TOKENS " %) .ESAMPLE -The CONDITION is a very limited expression whose format is determined -by its first keyword. +The CONDITION is either an expression whose format is determined by its +first keyword, or a string literals comparison or a numeric literals +comparison. .PP If the first part is the identifier .BR kernel_vr " or " kernel_v @@ -222,6 +229,10 @@ then the second part is one of the two s and the third part is a string literal for matching it. This comparison is simple string (in)equality. .PP +Otherwise, the CONDITION is expected to be a comparison between two string +literals or two numeric literals. In this case, the arguments are the only +variables usable. +.PP The TRUE-TOKENS and FALSE-TOKENS are zero or more general parser tokens (possibly including nested preprocessor conditionals), and are pasted into the input stream if the condition is true or false. For Index: b/testsuite/parseko/preprocess10.stp =================================================================== --- /dev/null +++ b/testsuite/parseko/preprocess10.stp @@ -0,0 +1,4 @@ +#! stap -p1 + +# expected number as right value in comparison +%( $# != "2" %? probe begin { } %) Index: b/testsuite/parseko/preprocess11.stp =================================================================== --- /dev/null +++ b/testsuite/parseko/preprocess11.stp @@ -0,0 +1,4 @@ +#! stap -p1 + +# expected string as right value in comparison +%( @# != 2 %? probe begin { } %) Index: b/testsuite/parseko/preprocess12.stp =================================================================== --- /dev/null +++ b/testsuite/parseko/preprocess12.stp @@ -0,0 +1,5 @@ +#! stap -p1 + +# command line argument index invalid or out of range +# (try to access to an unavailable argument) +%( $# < 2 %? probe begin { print @1 } %) Index: b/testsuite/parseok/fourteen.stp =================================================================== --- a/testsuite/parseok/fourteen.stp +++ b/testsuite/parseok/fourteen.stp @@ -15,3 +15,14 @@ global %: %( arch != "x86_64" %? other %: x86_64 %) %) %) + +global +%( $# != 2 %? /* and */ + %( @# < "1" %? /* and */ + %( @# == "0" %? /* and */ + %( $# >= 3 %? /* and */ + %( $2 >= "12" %? $3 FAIL5 %: $2 FAIL6 %) #This line must not be evaluated + %: PASS2 %) + %: "FAIL7" %) + %: "FAIL8" %) +%: "FAIL9" %) Index: b/testsuite/ChangeLog =================================================================== --- a/testsuite/ChangeLog +++ b/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2007-04-04 Pierre Peiffer + + * parseok/fourteen.stp: Add test about $# and @# usage during + the preprocessing. + * parseko/preprocess10.stp: New test. + * parseko/preprocess11.stp: New test. + * parseko/preprocess12.stp: New test. + 2007-03-22 Frank Ch. Eigler PR 4224. --------------080207050307060304030407--