How can an interpreter run code without translating into machine code?

I’m in my intro classes and trying to understand how a Java compiler works. Most posts said a compiler translates A to B (which could be machine code) to run, while an interpreter ‘just’ runs the code. How can the machine run code with just an interpreter, without producing or translating the code into machine code? Does it call built-in precompiled code of the functions it needs? If not, how can the machine run it? I learned it only understands bits.

3

An interpreter is nothing more than a computer program (usually compiled to machine code) that’s designed to execute other computer programs.

Like a compiler, an interpreter contains logic to read source code files, parse it (to understand its structure and syntax), and perform semantic analysis.

The difference is that an interpreter does not convert the program instructions to native machine code. Instead, it executes the program itself. You might think of an interpreter as an emulator for a virtual “computer” specially designed to support the interpreted language. This virtual computer will provide:

  • The “memory” in which the interpreted program will store its variables, function call stack, etc. Perhaps this will be a hashtable mapping interpreted-language variable names to objects. Memory can be dynamically allocated and deallocated as needed.
  • A means of implementing variable assignments (updating the aforementioned “memory” structure), function calls, or other control flow.
  • A means of handling any errors/exceptions that occur within the interpreted program.
  • A runtime environment that includes the interpreted language’s built-in functions and modules for doing math, I/O, etc.

The core of an interpreter is basically just a giant for loop that iterates over the interpreted program’s instructions and executes them one at a time. (See @Eik Eidt’s answer for a simple example.) Non-sequential execution (as with goto statements, ifelse statements, or function calls) can be implemented by changing the for loop’s “current instruction” index.

It’s common for interpreted languages to use some kind of intermediate representation that’s easier for the intepreter to work with than raw source code. This can be a “tokenized” representation of the source code, an abstract syntax tree, or a bytecode format that may closely resemble actual machine code. This intermediate representation may be an internal implementation detail that exists only in memory, or it may be saved as a “compiled” file on its own (as with Java .class files or Python .pyc files). The interpreter then executes the immediate representation.

There is also the hybrid approach of just-in-time compilation, which compiles the program to machine code at runtime and then runs it using the actual computer hardware. This tends to provide higher performance than normal interpretation.

1

You can write a simple interpreter.  Let’s make a language that “A” means print Hello and “B” means print Space and “C” means print World, then null means end program.

void interpret ( char *input ) {
   for (;;) {
       switch ( *input++ ) {
       case 'A' : printf ( "Hello" ); break;
       case 'B' : printf ( " " ); break;
       case 'C' : printf ( "World" ); break;
       case 'D' : printf ( "n" ); break;
       case '' : return;
       }
   }
}

interpret ( "ABCD" );  // prints "Hello Worldn"
interpret ( "CBAD" );  // prints "World Hellon"

There!  That’s an interpreter for a simple language.  More complex language, then more complex interpreter.  There’s no need for machine code translation here — except that this C program has to be compiled.

The point is that this interpreter, by just being a regular program, can do what is necessary to perform the operations in the input — it has all it needs to do the work of the input language.

2

Every programming language has semantics. These semantics are what a program means, and it defines what actions should be taken when one “runs” the program.

An interpreter reads in a program, parses it, and then does the actions that the semantics of the programming language says should be done when one “runs” the program.

A compiler reads in a program, parses it, and then instead of doing the actions, it writes out instructions in another language* which, if you “ran” that second program, the actions that should be taken are the same as the actions that should have been taken for the first program. The important distinction is that the compiler doesn’t actually do those operations. It allows one to “run” the outputted program to do them later.

There’s a bit of wishy-washyness around “run,” which is why I put it in quotes. For 99.9% of programing, we will say one “runs” machine code. So if a compiler outputs a program in machine code, we say all that’s left to do is “run” it. However, it’s turtles all the way down. At the CPU level, “running” machine code actually ends up being another interpreter step, converting it from machine code to microcode, and then “running” that microcode. And at the gate level, “running” the microcode is really just a set of massively parallel operations on the voltages at different transistors in the CPU. And even ignoring that, there’s emulators, which interpret machine code into something that can be run on different machines.

I give those examples to point out that yes, the concepts of interpreting and compiling have some funny overlaps, dealing with the question of what is “running.” But for the most part, your intuition about what is running is generally an effective one.

*. Or rarely: in the same language but a different form.

I don’t understand how an interpreter can run the code without producing or translating the code into machine code

By using facilities of the language the interpreter is written in which are compiled to machine code. Erik Eidt’s answer gives an example with a basic interpreter written in C, and it runs the interpreted code by calling C functions like printf.

Does it have a built-in precompiled code of the functions it needs, and then it calls them?

Yes… although maybe not in the way that you seem to think. It has the code of the language the interpreter is written in, and it translates the interpreted code on the fly into procedure calls in the interpreter language.

For example, Python has the print function. If you wanted to write an interpreter for Python in, say, Golang you’d have to analyze the details of the print function and then write Go code to implement what Python’s print function does, which is a lot more involved than just writing something to STDOUT (for instance it calls str() on its argument meaning you’d have to implement the sematics of that too), although for a toy example you might just call fmt.Println instead of actually implementing Python’s print.

If that sounds like a lot of work…well, it is. Writing an interpreter for any real programming language is a large task, which is why you should usually start with something simple like a toy scheme dialect.

First of all. Java programs are executed by a runtime environment that creates the equivalent of a virtual machine, it is visible by your OS as a normal process, but what the OS see is the java runtime not the specific java program.

Second. Since when Java was created dozen of different implementations of the runtime environment came out. They more or less follow similar guidelines, but it is not strictly fixed.

With most of the runtime environments (standard way) Java programs go through two steps. 1) Translation into bytecode to generate the .class files and packages. 2) Just in time compilation.

  • Step 1. The code is translated into bytecode. This step technically is a precompilation, but when you execute a build (by maven, gradle or similar) it is called the compilation step, which sometimes creates confusion. The bytecode and the package that is created is not machine code, but a common instruction set that can be executed on any host OS type, provided you have the runtime installed.

  • Step 2. When the execution of the java program is launched the runtime environment calls the Just-in-time compiler, translates the bytecode into machine code and executes it. Some non-standard runtimes use a bytecode interpreter, but if you use the common JDK or the original Sun JVM (now Oracle) there is no interpreter.

Exception. Many runtime environments now include a console for quick tests and syntax checks. They include a framework that will build everything, including the main, around the lines of code you write. Those will be executed on the fly and maybe by an interpreter.

4

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật