Definition
An interpreter is a program that reads source code and executes its behaviour directly, without producing a separate machine-code binary. The interpreter walks the program one expression or statement at a time, looks up what each construct means, performs the corresponding actions on its in-memory state, and moves on. The source code is the deliverable; the interpreter is what gives it life.
This contrasts with a compiler, which translates the entire program into native machine code ahead of time and then runs that machine code without further involvement. Interpreted languages include Python, Ruby, JavaScript (in many implementations), bash, and the historical lineage of Lisp. The boundary is fuzzy — many "interpreted" languages secretly compile to bytecode first — but the user-facing trait is that you run the source file directly with a single command, no separate build step.
Why it matters
How it works
A pure interpreter has three phases: lex (split the source text into tokens like keywords, identifiers, numbers, and punctuation), parse (assemble tokens into an abstract syntax tree describing the program's structure), and evaluate (walk the tree, performing the actions each node represents). State — variable bindings, open files, the call stack — lives in memory inside the interpreter process, not in the program itself. When you write x equals five in Python, the interpreter creates an entry in its current namespace mapping the name x to the integer object five; the source text is forgotten the moment the line is processed.
Most modern interpreters do not stop at tree-walking. CPython compiles each module to bytecode once, then runs the bytecode in a stack machine — faster than re-walking the syntax tree on every loop iteration. JavaScript engines like V8 go further, observing which bytecode runs frequently and just-in-time compiling hot paths into native machine code. The line between "interpreter" and "compiler" therefore lives on a spectrum: at one end the AST tree-walker for a teaching language, at the other end PyPy's tracing JIT that often beats hand-written C for numeric loops. The shared trait that keeps them all "interpreted" is the no-separate-build user experience.