compilationprogramming-languagesinterpreted-language

How does an interpreter run code?


Reading all the compiled vs interpreted articles it seems like compiled means the machine will run the compiled code directly whereas interpreted, the interpreter will run the code. But how does the interpreter run the code if it's on a machine? Doesn't it still end up having to convert what it's interpreting into machine code and STILL having the machine run it? At the end of the day, everything has to end up being machine code in order for the machine to run it right? It seems like interpreted just means that it's running through the language one line at a time whereas compiled means going thru it all at once. After that, it's pretty much the same right?


Solution

  • Related: How programs written in interpreted languages are executed if they are never translated into machine language?

    No, it doesn't need to convert it to a machine code. The instructions merely provide instructions to the interpreter itself, which the interpreter then executes itself.

    Consider a really dumb "language" that consists of the following instructions:

    add [number]
    subtract [number]
    divide [number]
    multiply [number]

    We could implement an "interpreter" like this (written in C#):

    public static void ExecuteStatements(List<string> instructions)
        {
            int result = 0;
            foreach (string instruction in instructions)
            {
                string[] action = instruction.Split(' ');
    
                int number = int.Parse(action[1]);
    
                switch (action[0].Trim().ToLower())
                {
                    case "add":
                        result += number;
                        break;
                    case "subtract":
                        result -= number;
                        break;
                    case "divide":
                        result /= number;
                        break;
                    case "multiply":
                        result *= number;
                        break;
                }
            }
    
            Console.WriteLine("Result: " + result);
        }
    

    The ExecuteStatements method will be compiled to machine code. Separately, we have a text file like this:

    add 1
    subtract 1
    add 10
    multiply 50
    divide 5

    The result will be 100. The strings are never actually compiled to anything - they just tell the interpreter what actions to take.

    Obviously, this "language" isn't even close to Turing-complete, but the point is that at no point are we somehow "translating" this into machine code - the "interpreter" just takes whatever action is specified.

    I actually wrote an interpreter once as part of a Test Automation framework. When someone did a call against the API, we would intercept the call, use reflection on it to determine what the call was and what the parameters were, and serialize the reflection metadata to JSON. We then later deserialized the JSON and used reflection to call whatever methods had been run before with the same parameters. The engine consumed JSON, not machine code, and used that to figure out what calls it should perform; at no point did it create or need any machine code. The critical thing was that, assuming that it had been given a valid script, the engine "knew" how to perform all of the specified actions itself, so it never needed to "offload" any of the instructions to the machine itself.

    Here's the key insight: the interpreted code itself is quite literally doing nothing - all it's doing is feeding the interpreter which actions it needs to take. The interpreter already "knows" how to take all of the actions you can perform in the interpreted language, so no additional machine code is required.

    As an analogy, think of the code you're interpreting as a recipe and the interpreter as a cook. The recipe specifies actions like "add 1 cup of flour and mix." The cook knows how to follow whatever directions he finds in the recipe and he performs them himself. Strictly speaking, the recipe isn't actually doing anything - it's just sitting there for the cook to read so that the cook can know what actions to take. There's no need for the recipe to actually be a cook in order for the recipe to be completed - it just needs someone who knows how to follow its directions.

    TL;DR You don't need to "translate" it into machine code - you just need to have enough information for your interpreter to know what actions to take. A good interpreter already "knows" how to take whatever actions the language could implement, so there's no need to create any additional machine code.