Re: Builtin Interpretation

"cr88192" <cr88192@hotmail.com>
Wed, 6 May 2009 12:41:22 -0700

          From comp.compilers

Related articles
Builtin Interpretation herron.philip@googlemail.com (Philip Herron) (2009-04-29)
Re: Builtin Interpretation bartc@freeuk.com (BartC) (2009-05-03)
Re: Builtin Interpretation herron.philip@googlemail.com (Philip Herron) (2009-05-05)
Re: Builtin Interpretation cr88192@hotmail.com (cr88192) (2009-05-06)
| List of all articles for this month |

From: "cr88192" <cr88192@hotmail.com>
Newsgroups: comp.compilers
Date: Wed, 6 May 2009 12:41:22 -0700
Organization: albasani.net
References: 09-05-001
Keywords: interpreter
Posted-Date: 07 May 2009 07:32:43 EDT

"Philip Herron" <herron.philip@googlemail.com> wrote in message
> I am getting on much better with my programming language i am making
> at the moment, when i get it to a decent state I'll send around the
> link.
>
> Anyways, this doesn't affect me but i was thinking about interpreters,
> say you have a programming language which needs to like read/write to
> a file or otherwise some System interface call, so for that
> programming language the library for doing that is probably written in
> its own language, but when it comes down how does it exec:
> fopen()... or otherwise...
>
> Or more precisely how does it know to do such a thing, is it that
> there is a special built-in keyword which the interpreter picks up to
> know hey we need to do 'X'. Thats one way i think it could be done,
> but is that the way most things do it? I need to do some more reading
> into interpreted languages.


My usual approach was to implement a "reasonably clean" bytecode, but also
have a way so that external functions can be simply "registered with" the
interpreter (basically, in C this would be via function pointers /
callbacks).


for example:
static fooElem foolang_fopen(FooContext *ctx, fooElem fname, fooEem fmode)
{
        FILE *fd;


        fd=fopen(fooStringv(fname), fooStringv(fmode));
        if(!fd)return(FOO_NULL);
        return(fooBoxPtr(fd));
}


static fooElem foolang_fread(FooContext *ctx,
        fooElem buf, fooEem sz1, fooElem sz2, fooElem fd)
{
        int i;
        i=fread(fooArrv(buf), fooIntv(sz1), fooIntv(sz2), fooBoxPtrv(fd));
        return(fooInt(i));
}


...


void FooLang_InitBuiltins()
{
        ...
        fooRegister("io.fopen", foolang_fopen, 2);
        fooRegister("io.fread", foolang_fread, 4);
        ...
}


this would be for a dynamically typed interpreter, but it would not be too
much different for an untyped interpreter (much more common in implementing
a statically typed interpreter, such as JVM, where the central rule is
typically what one can fit in a pointer...).


it is most convinient IME to pass the arguments in fixed-form, but it is
typically easier to pass them in an array. the number with "register"
indicates how many args to pass.


typically, in my case I had used negative argument counts for variable
numbers of arguments, where the number indicates the number of fixed
arguments, and the rest goes into a "rest" array or list (-1 means 0 fixed
args and 'rest', -3 means 2 fixed args, ...).




for a more "proper" statically typed VM, one will likely also need to pass
in a function signature. in my case I use a custom syntax combining the
JVM's notation and the IA-64 name-mangling scheme, so the above would be:
"io/fopen(PcPc)PXFILE;"
"io/fread(PviiPXFILE;)i"


with a little more work (in my case it is via automatically-generated
machine code, but plain old ASM would work), one can actually support
calling functions in the native calling convention, thus bypassing the need
to mashall and unmarshall function arguments.


and, in a related effort, one can eliminate the need to "register" functions
as well (both Windows and Linux provide mechanisms to lookup function
addresses by name).


all this makes interfacing with C land far more transparent...
(note that, for the most part anymore I use compilation to native code, and
not interpreters, but even as such there are cases where it is needed to be
able to dynamically call into C code, so all the above still applies...).


...




but, for starting off (the plunge into full static typing is something I
would delay until much later, as it is not nearly as easy as it might seem),
I would recommend taking the original approach with mashalled arguments and
registration (either via dynamic typing or untyped arguments...)


here is how an untyped varargs function could look:
static void *foolang_writestrings(FooContext *ctx,
        void *fd, void **rest, int nrest)
{
        int i;
        for(i=0; i<nrest; i++)
                fputs((char *)args[i], (FILE *)fd);
        return((void *)1);
}


(note: untyped args can be wrapped to look like the dynamically typed
example, only that the above makes it a little clearer what would be going
on in the untyped case...).


Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.