Programming is one of my hobbies and my dream is to do an interpreter on my own, but most books are so heavy to understand if you know what I mean.
Thank you very much for your opinion.
Programming is one of my hobbies and my dream is to do an interpreter on my own, but most books are so heavy to understand if you know what I mean.
Thank you very much for your opinion.
You'll probably get to the end and find that your first implementation "cheats", whatever that means. That's fine, improve it.
Write the memory model as a contained module, and have the interpreter core call into it.
Build an internal representation of a program, then make reading the source code a separate step from running it. Once you have that representation, some opportunities arise: e.g. represent increment and decrement as "add 1" and "add -1" instead.
Then you can write your first optimiser: turn long runs of increment and decrement instructions in the source code into a single "add n" instruction.
At this point, you have modules that turn source code into an internal representation, optimise the internal repr, and execute it. Start thinking of commands you can add to the language. Start thinking of how to handle data in the source code, rather than just instructions. How to build functions.
When you get to this point, you'll realise that you're no longer thinking "I wonder how an interpreter works", but rather "I wonder how you implement this particular part of an interpreter", and that is a much easier question to find answers for.
As a matter of fact, I wrote this book specifically for people like you and me: no CS degree, highly interested in interpreters and compilers, but intimidated by the existing literature. (If you studied compilers in college, this book will probably teach you nothing new.) There's a sample on the landingpage that should give you an impression of the difficulty - my guess is, that if you already know how to program and know the basics of Go, you'll get along just fine.
You can work through Sedgewick's Algorithms course on Coursera to get a stronger foundation for the more technical aspects of compiler writing.
You can study Stanford's Compilers course online: https://lagunita.stanford.edu/courses/Engineering/Compilers/...
A couple of years ago, I wrote https://github.com/steveklabnik/mojikun , which is an implementation of Brainfuck. I specifically over-engineered it to be more like a real interpreter than the smallest possible code, so it's actually split into parser/lexer/runtime/interpreter. I also made it have a more strongly-typed AST, which in retrospect is a little silly, at least the way that I did it. A bunch of those files have empty classes for this purpose.
Anyway, my overall point is, this project has the same structure as a "real" interpreter, and it's like 160 lines of code for the core functionality, no complex algorithms. And you can move on to harder languages fairly easily, and learn as you go.
I had the same feeling, so I tried it out myself. Inspired by Jonesforth (highly recommended), I wrote an arguably complete Lisp interpreter in a single, heavily commented ARM assembly language file.
Lisp is an obvious target, with its minimal syntax and simple concepts. The first Lisp was written in assembly on a machine with comparable capacity to your laptop keyboard's microcontroller, after all.
I hope you find it useful:
Now I'm sort of a serial language designer/implementor and pump out virtual machines on a regular basis. This stuff is really easy until you want to make it fast, then it gets really hard. ;-)
Just for starting out, I think you should basically make parsing as simple as you can. It's probably the most confusingly computer-sciency part of language implementation… and also probably the least important. So just avoid it. Maybe write a Lisp or Forth if you want. I actually advocate just using a very small simple (pascal-like) syntax though, and writing an operator-precedence parser. You'll learn more that way.