Also note that there's a Perl-space global named variable being initialized to hold the pointer to a C++ object - even before the user script is run.
This particular example plays with calling perl code from within C++, passing simple scalar arguments in and out, and evaluating anonymous subs and calling them by CV from C++ space (as there's no sub name to use).
This particular example contains no Threads.
Lessons learned (see the example code):
sub { # your custom code here }
You can either instruct the user programmer to do this in every method
of your program, or you can do this wrapping yourselfs behind the scenes.
Next, you pass the resulting text to perl_eval and POP the SV* result off
the Perl stack. Yes, the piece of code can immediately return a value at
eval time, as can be seen in some examples in the available documentation.
The very next thing you do, you have to SvREFCNT_inc() it to prevent its
mortality to take effect upon the next FREETMPS - see above.
In our case, the SV* returned is a Perl reference to CV - just like in
all the Perl-space examples, featured in standard documentation, where
a scalar is "assigned a reference to an anonymous sub".
As we're really interested in the CV* referenced, rather than the
(SV*) CVref holding it, alternatively we can let FREETMPS clean up the
reference, but in that case we need to increase the refcount of the CV,
so that it doesn't go down the pipes with the reference we're letting go.
Then, we can return the bare CV* out of our "anon sub eval wrapper" function.
CV* perl_eval_anon_sub(SV* source_text_to_parse);
It took me a busy saturday afternoon to find out that I was perhaps looking for something that was conceptually unsubstantiated and objectionable.
I started by looking at perl_eval_sv(), I found a call to entereval(),
calling doeval(), calling yyparse() - I was already lost two steps back,
as the original chunk of source code text got embedded into an SV* and
pushed on the Perl stack somewhere, obscured by all the macros and
"current thread" references. Further calls deeper into the perl guts
had little or no parameters (see yyparse()) and no documentation as to
how they pass data in and out.
In other words, after the call to perl_eval_sv() I lost the trace of my source
code chunk and found that I probably wouldn't find an internal call to create
an anonymous sub.
Then I started from perl_get_cv(), which looks for a sub by name and returns
its CV*. In other words, it's not much use for anonymous subs. But, it has
the option to return an empty CV if the sub name is not found in the symbol
tables. Which it does by a call to newSUB(), passing it a NULL instead of
"OP* block". In other words, there's an internal function named newSUB
that takes a tree of OP's (passed by a pointer to its root) and converts these
into a sub, returning its CV. If you pass a null name to newSUB (and perhaps
a special CVf_ANON flag to start_subparse(), which is used to initialize one
of its parameters), you get an anonymous sub by its CV.
Now the question was, how do I convert my snippet of source code text into
an OP* block?
I took a better look at perly.c and perly.y in the Perl source code. This was
where initially I found the call to newANONSUB. I recalled some cryptic
notes about a tool called YACC, that I'd met in the Perl newsgroups and
some literature side notes (or perhaps forewords).
Perhaps the odd two-line quote from the LOTR helped a bit, too.
The pieces of the puzzle snapped together and I found that in perly.y,
I was looking at the specification of Perl's syntax parser in some
higher-level language. It took me a minute to read the yacc manpage to confirm
that indeed perly.y was translated into perly.c. I proceeded to look at
where newANONSUB is called from, how it is invoked, what its parameters are.
When I proceeded from the specification of "block" to "lineseq" and found the
recursive grammar specification, and I found that a large part of perly.c is
the definition of yyparse(), another piece of the puzzle snapped in:
it dawned on me how perl_parse(), perl_eval_sv() & friends worked.
To sum up, the piece of Perl source to be parsed is inserted into an SV*,
pushed onto the Perl stack and further entangled in the obscure Perl guts.
Somehow, behind all the macros and intricate stack-machine clockwork,
it is passed to yyparse() (after some necessary yacc guts are bootstrapped).
In the form of a call to yyparse(), control is taken over by the
yacc-generated syntax parser (yacc-generated C code).
The yacc parser fumbles through the code, possibly creating some yacc'ish
meta-structures (lexical tree) in the process - at the same time, whenever
it encounters a grammar element, it acts according to the specification
from the .y file: where specified, it calls C-space functions (syntax parsing
Perl guts), that effectively build up the OPcode tree (C space, Perl guts
space). When yacc-generated code is done lexically parsing the given snippet
of Perl code, perl guts are done building the opcode tree.
Back to my original intention. Apparently, there's no such thing as an
perl_eval* API call to evaluate a single sub based on (char*) souce code
passed to it.
There's an internal call, returning the CV of a sub, specified by a root OP*
of the block comprising its body. This call is used internally by a wrapper
that takes this CV* and embeds it in yet another OP* (a subroutine call
OPcode, probably), that's used by the yacc-generated parser as an input
for some more OPcode-tree-building perl guts...
If I wanted to use raw newSUB() to get me a CV built from my Perl text,
I'd have to mimick the yacc guts that normally create the "OP* block",
a crucial input parameter to newSUB(). Or, I'd have to force raw
yyparse() to convert the piece of source code text for me, so that
I could pass the OP* to newSUB(). Neither of which seems to be a trivial
task - this isn't even Perl guts, this is yacc guts!
I decided I wasn't going that way.
After this mental exercise, the clear solution is to add to my subroutine body a Perl-space definition of an anonymous sub, which will return a (CV ref*) SV* straight back into C++ space, using perl_eval_sv().
The moral is: perl_eval_sv() and all of its lookalikes/wrappers are meant to
evaluate a snippet of Perl code in general - not strictly formatted into the
lexical element known as a sub. The distinction of an "anonymous sub" (and
subs in general) as a lexical element is an internal affair of the
yacc-generated lexical parser.
The internal calls to newSUB and newANONSUB are entangled into the parser
framework to the extent that they're hardly any use in a potential stand-alone
context.