public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* 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).