Interpreters – Chain of Interpretations to the Lowest Level

interpreters

After doing some research and with the help of people on this site, I finally came to an understanding of what interpretation actually is.

Essentially, what interpretation means is (correct me if I'm wrong):

  1. Scan a piece of code.
  2. Come up with a piece of code in another language, with the same meaning.
  3. Execute that new piece of code.

So for example, and interpreter written in Java that interprets code in C, and sees this line of code:printf("hello world");

Will come up with this line of code: System.out.println("hello world");

And will execute it (as opposed to a compiler, which will store it).

If all of this is true, then here is my question:

I think, that every execution an interpreter carries out, actually creates a chain of interpretations down to the lowest level. I'd like to know if this is true. Here is what I mean:

When an interpreter executes a line of code (which is the new line it came up with, after scanning a line), it actually tells the underlying platform to interpret it.

For example, as we know, an interpreter written in Java that interprets C code, sees printf("hello") and executes in reaction the new line of code System.out.println("hello").

But what does "executes System.out.println("hello")" actually mean? It means to tell the underlying platform (in this case the JVM) to interpret this line.

And so, another interpretation begins: The (in this example) interpreter in the JVM receives the line System.out.println(), comes up with a new line of code with the same meaning in another language, and executes it.

And when it executes the new line of code, again: It actually tells it's underlying platform to interpret it (in this example, the OS). And then another interpretation begins in the OS, which comes up with a new line of code with the same meaning in a different language, and tells an even lower level to interpret it. This continues down to the lowest level of the CPU.

My question is: Is this true? Is every execution an interpreter carries out, actually a call to the underlying platform to interpret? (Thus creating a chain of interpretations down to the lowest level?)

When people say that an interpreter executes code, do they actually mean that it tells it's underlying platform to interpret that code? (And so on?)

(Note: I might be not accurate about the function of the JVM specifically, I missed some steps there. But my question is more general, Java is just an example).

Best Answer

Yes, but more than that. All of the interpreter's code is interpreted by a lower level, including the "scan a piece of code" step.

However, there are less levels than you think - more than three levels is rare. Jython is one example of an interpreter running on an interpreter. It runs Python code, and is itself written in Java, which is interpreted by a JVM, which is machine code (that was compiled from C or C++) which is interpreted by the CPU.

JVMs commonly are written in C or C++, and run directly on the CPU, not the OS. Native programs run directly on the CPU, alongside the operating system, rather than being interpreted by the operating system. The difference between the OS and a native program is that the OS has more access to the hardware, so that if the native program wants to access the hardware (e.g. to display stuff on the screen) it still needs to ask the OS.

Also, the "coming up with a line of code in a new language" is Just-In-Time Compilation, not strictly interpretation. Many programs traditionally thought of as interpreters (including nearly all JVMs) do use some form of JIT compilation. A JIT compiler looks something like this:

void execute(instruction instructions_to_execute[])
{
    lower_level_function f;
    if(is_translation_in_cache(instructions_to_execute))
        f = get_translation_from_cache(instructions_to_execute);
    else
    {
        f = translate_to_lower_level_instructions(instructions_to_execute);
        put_translation_in_cache(instructions_to_execute, f);
    }
    f();
}

while an interpreter looks like this:

void execute(instruction instructions_to_execute[])
{
    for(instruction i in instructions_to_execute)
    {
        switch(i.type)
        {
        case PRINT_STRING:
            print(i.string_to_print);
            break;
        case ADD:
            variables[i.result_variable] = variables[i.left_variable] + variables[i.right_variable];
            break;
        case CALL:
            execute(functions[i.function_to_call].instructions);
            break;
        // etc
        }
    }
}

JIT compiling is usually faster for frequently run sections of code, because they can be converted into the lowest level code, and then executed directly. Interpreting is faster for sections of code that are infrequently executed, because the compiler (the translate_to_lower_level_instructions function) is slow.

Related Topic