[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

More JNI vs. Pika comparison



I've come across a situation which is reasonably straightforward to
handle in a JNI-style interface, but which I think requires machinery
I haven't seen yet in Pika-style.  I'd like to see the Pika folks'
solution here.

When I write actions for a Bison grammar, it's pretty straightforward
to use Minor references in the semantic actions.  I've included most
of the .y file here in case someone wanted all the details, but skip
down to the list_data nonterminal to see what I'm talking about.

(I'm inflicting untested code on you folks again.  I'll earn some kind
of gonzo reward eventually.  Sorry.  But I think the point is safe
enough.)

%{

/* The type of Bison semantic values.  */
#define YYSTYPE mn_ref *

/* Our parser takes an mn_call, cast to a void *, as a parameter.  */
#define YYPARSE_PARAM untyped_call
#define c ((mn_call *) untyped_call)

%}

%pure_parser

%token CHARACTER
%token FALSE
%token IDENTIFIER
%token NEWLINE_CHARACTER
%token NUMBER
%token SPACE_CHARACTER
%token START_VECTOR
%token STRING
%token TRUE
%token UNQUOTE_SPLICING

%%

datum: simple_datum | compound_datum;

simple_datum: boolean | NUMBER | character | STRING | symbol;

boolean: TRUE | FALSE;

character: SPACE_CHARACTER | NEWLINE_CHARACTER | CHARACTER ;

symbol: IDENTIFIER;

compound_datum: list | vector;

list: '(' list_data ')' { $$ = $2 };

list_data:
    datum list_data { $$ = mn_to_cons (c, $1, $2); }
  | datum '.' datum { $$ = mn_to_cons (c, $1, $3); }
  |                 { $$ = mn_null (c); }
  ;

vector:
    START_VECTOR vector_data ')'
      { 
        $$ = mn_list_to_vector (c, $2);
        mn_free_local_ref (c, $2);
      }
  ;

vector_data:
    datum vector_data { $$ = mn_to_cons (c, $1, $2); }
  |                   { $$ = mn_null (c); }
  ;

%%

The underlying issue here is that we want the generated parser's stack
of semantic values to hold references to Scheme objects.  Since a
JNI-style interface works on pointers to dynamically allocated
references, one can simply declare semantic values to be such
pointers, as we do with the #definition of YYSTYPE above.  We use
"linear" functions like mn_to_cons to free intermediate references.
If the parser exits with an error, any local references on the stack
are freed properly when the mn_call returns.

It seems to me that handling this in Pika requires one to use a
separate facility that hasn't been described on this list before,
which allows Pika references to appear inside other data structures,
gives them dynamic lifetimes, and requires them to be explicitly freed
--- much as with a JNI-style interface.  Then, one writes code much
like the above.  And the user would need to write their own mechanism
for cleaning things up in the case of a parser error.

It seems to me similar problems will occur working with any
third-party tool that presumes it is sufficient to let people pass
around pointers to data of their own definition.

So, in the end, it looks to me as if Pika will need to provide a
JNI-style interface anyway, in addition to the C compound-statement-
bound interface, which would still be the preferred interface for C
code written against Pika interfaces.