Peeter Joot's (OLD) Blog.

Math, physics, perl, and programming obscurity.

regular expression driven code alteration

Posted by peeterjoot on September 2, 2009

Exersize. Have code with repeated blocks of (trace-stuff, return), like the following:

if ( foo )
{
   TraceData( TraceId, 10, NULL, 0 );
   TraceExit( TraceId, FALSE );
   return FALSE;   
}

...
if ( bar )
{
   TraceData( TraceId, 20, NULL, 0 );
   TraceExit( TraceId, FALSE );
   return FALSE;   
}

The function in question actually has many of these, and a goto would work well to consolidate them and make it harder to miss the TraceExit’s. Yes, some people will argue that gotos are evil, but I’m working with a codebase that uses them regularily to enforce a single return point, and there’s no point fighting with 20 years of historical inertia. We go with the flow, and add the following to the end of the function

TRACE_AND_EXIT:

    TraceData( TraceId, probe, NULL, 0 );
    TraceExit( TraceId, matched );

    return matched ;
}

Now, the job becomes taking this repeated three line sequence and replacing it with something that doesn’t generate two trace function calls at every return point, and avoids the multiple return points. That is

   probe = 10 ; matched = FALSE ;
   goto TRACE_AND_EXIT ;

Being lazy, but too playful for my own good, I recycle a previous simple but powerful code alteration script detailed in a previous blog post, and produce with only alteration of two regular expressions

while (<>)
{
   $p .= $_ ;
}

$p =~ s/^(\s+)(TraceData.*?return\s+.*?\S+ *;)/foo($1, "$2")/smeg ;
print $p ;

exit ;

my $probe = 0 ;

sub foo
{
   my ($leadingSpaces, $rest) = @_ ;

   # not bothering with the old probe points.  Just renumber them 10, 20, 30 ...
   $probe += 10 ;

   $rest =~ /return\s+(.*?) *;/sm or die ;

   return "${leadingSpaces}probe = $probe ; matched = $1 ;\n${leadingSpaces}goto TRACE_AND_EXIT ;" ;
}

I really only want to apply this to the body of the current function. I can do that by positioning myself near the beginning of the function in vi, and using this script as a filter to modify from the current line all the way to the goto LABEL that I just added:

,/TRACE_AND_EXIT/ !perl ./thisHackyScript

There’s a few new things in this one liner. Like all other vi commands, we start with a range of line numbers

:N,M

leaving off the first number means start from the current line. I’ve used a pattern instead of a line number for the end range for the vi command, so I want this to run til the expression TRACE_AND_EXIT is encountered. The last bit is to filter the output through a command, in this case the hacky little perl script above which I’ve put in the local directory as ./thisHackyScript

Now, I’ve also defaulted matched = FALSE in its declaration, so make a final cleanup pass in vi, again positioning myself near the beginning of the function:

,/^}/ s/ matched = FALSE ;//c

As above the beginning and ending line numbers for this alteration are the current line number and an expression, and the command to apply is the replacement of all ‘ matched = FALSE ;’ text with nothing. The c modifier at the end here is a very handy and says “prompt for all changes”. If you like what it is doing and haven’t made an error with your replacement expression (hard to do here), then answering the prompt with ‘a’ quits the prompt and just does it.

Finito. Now did this explaination make any sense… perhaps not. As a fall back you can grab the little filter script and play with it to figure it out and then have a nice little tool for some semi-automatic mucking around in your own code.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: