Aug 21, 1995, 4:10 PM
Post #9 of 11
(4016 views)
Permalink
From: Tim Bunce <Tim.Bunce@ig.co.uk>
>
>
> > From: Paul Marquess <pmarquess@bfsec.bt.co.uk>
> >
> > First off, I'm thinking of changing the way a Perl Source Filter (i.e.
> > a Source Filter written in Perl) gets installed. For those of you who
> > havn't been paying attention, it currently works like this
> >
> > use Filter::call qw(myfilter args) ;
> >
> > where 'myfilter' is the name of the Perl Source Filter module and
> > 'args' are any optional parameters that the filter may require. The
> > users filter module then has this sort of structure
> >
> > package myfilter ;
> > sub new { bless [] }
> > sub filter { code to filter source }
> >
> > Although this works fine, it doesn't seem quite right. What I think would
> > be better is for the end user to be able to type
> >
> > use myfilter ;
> >
> > and have the filter module to 'attach' itself to the source filter
> > low level code. Something along these lines:
> >
> > package myfilter ;
> > use Filter::call ;
> > sub filter { ... }
> > sub import { attach to Filter::call }
> >
> Fine by me.
>
> > This means that if the fabled Perl pre-processor (ppp) ever gets
> > implemented it can be used like this
> >
> > use ppp ;
> >
> > rather than this
> >
> > use Filter::call 'ppp' ;
> >
> > I personally think that this is a *much* better interface. Any
> > comments before I go and implement it?
> >
> Nope. Go for it!
ok.
> > Below is a complete source filter which will substitute every occurence
> > of the string "Today" into the string "Tomorrow". 'new' is used to
> > instantiate a new copy of the source filter and the 'filter' method is
> > the place where all the filtering takes place. I'm only concerned here
> > about the operation of the filter method.
> >
> > package Future ;
> >
> > sub new { bless [] }
> >
> > sub filter
> > {
> > my ($self, $buffer) = @_ ;
> > my ($status) ;
> >
> > if ($status = filter_read($buffer)) {
> > $$buffer =~ s/Today/Tomorrow/g
> > }
> > $status ;
> > }
> > 1 ;
> >
> >
> > The $buffer parameter is a reference to a scalar. The filter is
> > expected to return the source (after filtering it) via this reference.
> >
> > filter_read is used by the filter to say "give me another line". It
> > expects its first parameter to be a reference to a scalar as well and,
> > as I'm sure you have guessed, it returns the source line via that
> > reference.
> >
> > The use of references seems quite efficient (it does seem to cut down
> > on the amount of unnecessary copying of buffers) but I'm a bit uneasy
> > about it.
> >
> > So the question is - can anyone think of an interface which is cleaner
> > but is still efficient? Having lived with the current interface for a
> > while I think I could accept with the way I've done it, but I would
> > like to improve it if possible.
> >
> I think my original suggestion was to localise and use $_:
>
> sub filter
> {
> my $self = shift ;
> my $status ;
>
> if ($status = filter_read()) {
> s/Today/Tomorrow/g
> }
> $status ;
> }
> 1 ;
>
> I'm not quite sure what the right save_*() or SAVE*() function/macro to
> use is (maybe someone else does, should be easy to find) but I think
> this is a good approach.
Ah yes, I remember now.
The localised $_ model looks great for trivial filters, like the one
above. I just wonder if it would be appropriate for a filter which
required even a little bit more logic... then again, it might be ok :-)
Either way, I think it's worth investigating, so I could do with a few
hints on how to go about it.
Here is my first attempt. This code is used to call the 'filter'
method. The parts to do with manipulating $_ are highlighed.
dSP ;
int count ;
/* remember the current idx */
av_push(idx_stack, newSViv(idx)) ;
/* save current $_ */ <==========
av_push(def_stack, GvSV(defgv)) ; <==========
/* make $_ use our buffer */ <==========
GvSV(defgv) = OUTPUT_SV(my_sv) ; <==========
PUSHMARK(sp) ;
XPUSHs(PERL_OBJECT(my_sv)) ;
PUTBACK ;
count = perl_call_method("filter", 0) ;
SPAGAIN ;
if (count != 1)
croak("Filter::call - %s::filter returned %d values, 1 was expec
ted \n",
count, PERL_MODULE(my_sv)) ;
n = POPi ;
if (fdebug)
warn("status = %d, length op buf = %d\n",
n, SvCUR(OUTPUT_SV(my_sv))) ;
PUTBACK ;
sv_free(av_pop(idx_stack)) ;
/* restore $_ */
GvSV(defgv) = av_pop(def_stack) ; <============
and filter_read gets the $_ buffer like this
SV * buffer = GvSV(defgv) ;
Although the above code does seem to work ok, I would really like some
feedback on its correctness.
> > So... what do you think about the idea of having a ppp? I *might* be
> > prepared to give this a go, *if* there is enough interest.
> >
> Yes please. Certainly doing #define's, #if's and #ifdef's should be
> straightforward. Doing macro substitutions with parameters might be a
> little more tricky!
*If* I do it, it would only be #if #elsif #else #endif #define and
#undef. I wouldn't even attempt macros with parameters.
> But why do it in perl? Why not find a public domain CPP and include that?
> Much less effort and faster too.
Good point, anyone know of a public domain cpp implementation we could
use?
Only thing with using an existing cpp implementation is interfacing to
it. The simplest way would be to use Filter::exec, but I would kinda
like to avoid the sub-process method.
Making an existing cpp work with the filter_read model might be a
non-trivial task.
Paul