* Patch proposal 1/2: number of arg identifier @ 2007-04-03 14:39 Pierre Peiffer 2007-04-03 14:45 ` Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing Pierre Peiffer 0 siblings, 1 reply; 8+ messages in thread From: Pierre Peiffer @ 2007-04-03 14:39 UTC (permalink / raw) To: systemtap [-- Attachment #1: Type: text/plain, Size: 429 bytes --] Hi, Here is a proposal of patch which allows the access to the number of arguments passed to the script through the bash-like identifier $# and @# (the identifier is interpreted as tok_number or tok_string accordingly). In fact, I've done this for a colleague and found this useful. That's why I send it to this list, but just forget this mail if you don't like it ;-) I'll send a second proposal, anyway... -- Pierre [-- Attachment #2: allow-number-of-args-pattern.patch --] [-- Type: text/x-patch, Size: 2839 bytes --] --- ChangeLog | 5 +++++ parse.cxx | 48 +++++++++++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 19 deletions(-) Index: b/parse.cxx =================================================================== --- a/parse.cxx +++ b/parse.cxx @@ -501,7 +501,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 +514,34 @@ 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 (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,8 @@ +2007-04-03 Pierre Peiffer <pierre.peiffer@bull.net> + + * parse.cxx: Add $# and @# identifiers to access the number + of arguments passed as 'number' or as 'string'. + 2007-03-22 Frank Ch. Eigler <fche@elastic.org> PR 4224. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing 2007-04-03 14:39 Patch proposal 1/2: number of arg identifier Pierre Peiffer @ 2007-04-03 14:45 ` Pierre Peiffer 2007-04-03 15:09 ` Benjamin Thery 0 siblings, 1 reply; 8+ messages in thread From: Pierre Peiffer @ 2007-04-03 14:45 UTC (permalink / raw) To: systemtap [-- Attachment #1: Type: text/plain, Size: 415 bytes --] Hi again, Here is a second proposal to complete the previous one: this patch allows the use of $x or @x identifiers ($1 ... $n and $#, etc) during the preprocessing (in addition of kernel_v pattern, etc). Again, I originally have written this for a colleague and found this useful. So again: > That's why I send it to this list, but just forget this mail if you don't like it ;-) Thanks -- Pierre Peiffer [-- Attachment #2: allow-args-during-prepocessing.patch --] [-- Type: text/x-patch, Size: 5002 bytes --] --- ChangeLog | 5 +++++ parse.cxx | 51 +++++++++++++++++++++++++++++++++++++++++++++------ parse.h | 4 ++-- 3 files changed, 52 insertions(+), 8 deletions(-) Index: b/parse.cxx =================================================================== --- a/parse.cxx +++ b/parse.cxx @@ -146,6 +146,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 +214,49 @@ 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 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); } const token* -parser::scan_pp () +parser::scan_pp (bool expand_args) { while (true) { @@ -230,7 +267,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; @@ -262,7 +299,7 @@ parser::scan_pp () 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); @@ -282,7 +319,7 @@ parser::scan_pp () delete m; // "%:" while (true) { - m = scan_pp (); // NB: recursive + m = scan_pp (!result); // NB: recursive if (m == 0) throw parse_error ("missing ELSE tokens for conditional", t); @@ -473,7 +510,7 @@ lexer::input_get () token* -lexer::scan () +lexer::scan (bool expand_args) { token* n = new token; n->location.file = input_name; @@ -514,6 +551,8 @@ lexer::scan () // numbers and @1 .. @999 as strings. if (n->content[0] == '@' || n->content[0] == '$') { + if (!expand_args) + return n; if (n->content[1] == '#') { stringstream converter; Index: b/parse.h =================================================================== --- a/parse.h +++ b/parse.h @@ -64,7 +64,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 +124,7 @@ private: // preprocessing subordinate std::vector<const token*> enqueued_pp; - const token* scan_pp (); + const token* scan_pp (bool expand_args=true); // scanning state const token* last (); Index: b/ChangeLog =================================================================== --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2007-04-03 Pierre Peiffer <pierre.peiffer@bull.net> + * parse.cxx, parse.h: Allows the use of $x and @x identifier + during the preprocessing. + +2007-04-03 Pierre Peiffer <pierre.peiffer@bull.net> + * parse.cxx: Add $# and @# identifiers to access the number of arguments passed as 'number' or as 'string'. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing 2007-04-03 14:45 ` Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing Pierre Peiffer @ 2007-04-03 15:09 ` Benjamin Thery 2007-04-03 15:39 ` Frank Ch. Eigler 0 siblings, 1 reply; 8+ messages in thread From: Benjamin Thery @ 2007-04-03 15:09 UTC (permalink / raw) To: Pierre Peiffer; +Cc: systemtap Hi, I'm the aforementioned "colleague". My request was for a very simple stap script: As I often use Systemtap to display backtraces for routines either in the kernel or in modules, I wanted a generic script that takes either one or two arguments to set the probe (kernelsymbol | modulename modulesymbol). I didn't want to write a bash wrapper around two stap scripts (too much files for such a simple task :) ), so I asked Pierre and he developed this small patch. Useful. The script looks like this: #! stap # Trace all execution paths that lead to a given function in the # kernel or a specified module. # # Usage: stap kernel_symbol # stap module_name module_symbol %( $# < 2 %? probe kernel.function(@1) { printf("\n\n---------------------\n") print_backtrace() } %: probe module(@1).function(@2) { printf("\n\n---------------------\n") print_backtrace() } %) Can't be more simple. Benjamin Pierre Peiffer wrote: > > Hi again, > > Here is a second proposal to complete the previous one: this patch > allows the use of $x or @x identifiers ($1 ... $n and $#, etc) during > the preprocessing (in addition of kernel_v pattern, etc). > Again, I originally have written this for a colleague and found this > useful. > So again: >> That's why I send it to this list, but just forget this mail if you >> don't like it ;-) > > Thanks > > > ------------------------------------------------------------------------ > > --- > ChangeLog | 5 +++++ > parse.cxx | 51 +++++++++++++++++++++++++++++++++++++++++++++------ > parse.h | 4 ++-- > 3 files changed, 52 insertions(+), 8 deletions(-) > > Index: b/parse.cxx > =================================================================== > --- a/parse.cxx > +++ b/parse.cxx > @@ -146,6 +146,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 +214,49 @@ 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 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); > } > > > const token* > -parser::scan_pp () > +parser::scan_pp (bool expand_args) > { > while (true) > { > @@ -230,7 +267,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; > > @@ -262,7 +299,7 @@ parser::scan_pp () > > 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); > > @@ -282,7 +319,7 @@ parser::scan_pp () > delete m; // "%:" > while (true) > { > - m = scan_pp (); // NB: recursive > + m = scan_pp (!result); // NB: recursive > if (m == 0) > throw parse_error ("missing ELSE tokens for conditional", t); > > @@ -473,7 +510,7 @@ lexer::input_get () > > > token* > -lexer::scan () > +lexer::scan (bool expand_args) > { > token* n = new token; > n->location.file = input_name; > @@ -514,6 +551,8 @@ lexer::scan () > // numbers and @1 .. @999 as strings. > if (n->content[0] == '@' || n->content[0] == '$') > { > + if (!expand_args) > + return n; > if (n->content[1] == '#') > { > stringstream converter; > Index: b/parse.h > =================================================================== > --- a/parse.h > +++ b/parse.h > @@ -64,7 +64,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 +124,7 @@ private: > > // preprocessing subordinate > std::vector<const token*> enqueued_pp; > - const token* scan_pp (); > + const token* scan_pp (bool expand_args=true); > > // scanning state > const token* last (); > Index: b/ChangeLog > =================================================================== > --- a/ChangeLog > +++ b/ChangeLog > @@ -1,5 +1,10 @@ > 2007-04-03 Pierre Peiffer <pierre.peiffer@bull.net> > > + * parse.cxx, parse.h: Allows the use of $x and @x identifier > + during the preprocessing. > + > +2007-04-03 Pierre Peiffer <pierre.peiffer@bull.net> > + > * parse.cxx: Add $# and @# identifiers to access the number > of arguments passed as 'number' or as 'string'. > -- B e n j a m i n T h e r y - BULL/DT/Open Software R&D http://www.bull.com ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing 2007-04-03 15:09 ` Benjamin Thery @ 2007-04-03 15:39 ` Frank Ch. Eigler 2007-04-03 16:10 ` Benjamin Thery 2007-04-04 7:16 ` Pierre Peiffer 0 siblings, 2 replies; 8+ messages in thread From: Frank Ch. Eigler @ 2007-04-03 15:39 UTC (permalink / raw) To: Benjamin Thery; +Cc: Pierre Peiffer, systemtap Benjamin Thery <benjamin.thery@bull.net> writes: > [...] Can't be more simple. Sure it could: :-) probe %( $# < 2 %? kernel.function(@1) $: module(@1).function(@2) %) { ... } 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? - FChE ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing 2007-04-03 15:39 ` Frank Ch. Eigler @ 2007-04-03 16:10 ` Benjamin Thery 2007-04-04 7:16 ` Pierre Peiffer 1 sibling, 0 replies; 8+ messages in thread From: Benjamin Thery @ 2007-04-03 16:10 UTC (permalink / raw) To: Frank Ch. Eigler; +Cc: Pierre Peiffer, systemtap Frank Ch. Eigler wrote: > Benjamin Thery <benjamin.thery@bull.net> writes: > >> [...] Can't be more simple. > > Sure it could: :-) > > probe %( $# < 2 %? kernel.function(@1) $: module(@1).function(@2) %) > { ... } Argh, It seems I spoke too fast once again :-) I'll just fix a small typo in your code: "%:" instead of "$:" : probe %( $# < 2 %? kernel.function(@1) %: module(@1).function(@2) %) and voila. :-) > 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? > > > - FChE > -- B e n j a m i n T h e r y - BULL/DT/Open Software R&D http://www.bull.com ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing 2007-04-03 15:39 ` Frank Ch. Eigler 2007-04-03 16:10 ` Benjamin Thery @ 2007-04-04 7:16 ` Pierre Peiffer 2007-04-04 14:48 ` Patch: allow use of $x and @x Pierre Peiffer 1 sibling, 1 reply; 8+ messages in thread From: Pierre Peiffer @ 2007-04-04 7:16 UTC (permalink / raw) Cc: systemtap 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 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Patch: allow use of $x and @x 2007-04-04 7:16 ` Pierre Peiffer @ 2007-04-04 14:48 ` Pierre Peiffer 2007-04-04 21:18 ` Frank Ch. Eigler 0 siblings, 1 reply; 8+ messages in thread From: Pierre Peiffer @ 2007-04-04 14:48 UTC (permalink / raw) To: systemtap [-- Attachment #1: Type: text/plain, Size: 1231 bytes --] 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 [-- Attachment #2: allow-number-of-args-pattern.patch --] [-- Type: text/x-patch, Size: 14012 bytes --] --- 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<const token*> 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 <pierre.peiffer@bull.net> + + * 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 <fche@elastic.org> 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<const token*> 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 ... $<NN> for casting as a numeric literal and .B @1 ... @<NN> -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 <pierre.peiffer@bull.net> + + * 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 <fche@elastic.org> PR 4224. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: Patch: allow use of $x and @x 2007-04-04 14:48 ` Patch: allow use of $x and @x Pierre Peiffer @ 2007-04-04 21:18 ` Frank Ch. Eigler 0 siblings, 0 replies; 8+ messages in thread From: Frank Ch. Eigler @ 2007-04-04 21:18 UTC (permalink / raw) To: Pierre Peiffer; +Cc: systemtap Thank you, patch tested and committed. - FChE ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-04-04 21:18 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-04-03 14:39 Patch proposal 1/2: number of arg identifier Pierre Peiffer 2007-04-03 14:45 ` Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing Pierre Peiffer 2007-04-03 15:09 ` Benjamin Thery 2007-04-03 15:39 ` Frank Ch. Eigler 2007-04-03 16:10 ` Benjamin Thery 2007-04-04 7:16 ` Pierre Peiffer 2007-04-04 14:48 ` Patch: allow use of $x and @x Pierre Peiffer 2007-04-04 21:18 ` Frank Ch. Eigler
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).