How Difficult is it to Write a Compiler?
tratt.net
tratt.net
Yes, you can write a compiler in a few days, if you have done it before, if your target language semantics are compatible, if you wave you hands about usability, if you are the only user, and you don't give a rat's ass about performance. If you want to translate to a low level virtual machine like JVM or to machine binary, you have a lot more work to do: compiler optimization, instruction scheduling, register scheduling, etc.
Tratt's three steps are something that you might find in a Wikipedia article (but I haven't looked.) Generally you don't create a parse tree, unless are doing something like mapping back into a newer version of the target language or doing sophisticated macro expansion. Using Bison or a similar parser generator, you directly create an Abstract Syntax Tree (AST). Using the AST, you perform semantic checking (has the variable been declared, type compatibility in expressions...); language based optimizations like removing redundant expressions, loop hoisting, tail recursion; generate abstract machine code. Using the AMC, do machine specific optimizations like instruction scheduling (reordering to take advantage of the architecture); register scheduling; and finally generate the binary. All of which take more than a couple of days
That said, it's certainly not trivial, so it still might not qualify as "sane."
If you have actual compiler-writing tools then it doesn't have to take weeks or even days to write a compiler for a simple language --- if you don't care about performance, if the backend language isn't too much of a pain in the ass, if error reporting is not a major concern.
Thing is, though, performance doesn't matter any more. Oh, sometimes it does, yes. If you're writing a C compiler for a computer manufacturer, it certainly does. (Tip: port GCC instead.) But all those people who are using Ruby or Python or Perl or PHP? They aren't going to care if your compiler generates code that's 10× slower than it could be, because it's still 10× faster than what they're used to, and you can probably get them not to care that your compiler executes a million instructions per line of code that it compiles.
Kragen Sitaker has a great collection of links for amateur compiler writers on his Ur-Scheme (http://www.canonical.org/~kragen/sw/urscheme/) page.
This paper (http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf) by Abdulaziz Ghuloum is also very interesting - he shows step-by-step how to write a simple native-code Scheme-like compiler by writing small C functions, compiling them with gcc, and then saving the assembly output. ("Since we don’t know yet how to do that, we ask for some help from another compiler that does know: gcc.") Heavy theory about optimizing? Nope. Demystifying and inspiring? Heck yeah.
As an old compiler hacker (from the early 70s), what I've seen of LLVM is that it's a world-class foundation.
Apart from that, and the slowness of its instruction selector, though, it's pretty good.
In any case, I'd venture to say writing a simple compiler should be pretty easy these days with tools like LLVM - http://llvm.org/ - and the slew of lexers/parsers available for different platforms.
Hm, like what?
Calling conventions (argument passing protocols) are designed to be efficient for a particular CPU architecture. Scheduling algorithms try to make the best use of all resources while still meeting other performance criteria (e.g. firing events at roughly the right time). Register allocators are usually trying to produce the fastest code possible. And there are arguments both for and against big and little endianness, but I don't remember what they are. :-)
http://blog.fogus.me/2008/07/22/broccoli-v022-bellwitch/
Smalltalk has only about 8 terminals and nonterminals in its grammar. You can hand code a top-down parser for it in an afternoon.
Then there's always Forth.
I second the comments up-thread about error-reporting being the hardest part of a real compiler.
Although there's some mathematical theory in the background (regular expressions, context free grammars), the techniques don't fully correspond to them, and aren't really implementations of the theory, but a convenient, useful, doable subset. The adoption of the techniques seems to be dictated by what works to solve specific practical problems. The techniques themselves are pretty ad hoc; but they have been studied, and there is a body of knowledge about where each technique is applicable. Although certain correspondences have been proven, it's not neat and beautiful like physics; but truth and beauty aren't what ye need to know here.
It's really "Compiler Engineering".
http://video.google.com/videoplay?docid=7654043762021156507
There are course materials available for free download, including all of the programs and emulators, which are Open Source.
I understand that writing a good compiler is somewhat more difficult.
Also depends on how you define what's good.
You might want a compiler to give good CPU performance, memory, code size, debugging information, robustness, start-up speed, etc.
Some of these can be difficult - any combination is even more difficult again.
http://www.cdc.gov/od/ohs/biosfty/bleachiv.htm
Also reminds me of the rube who couldn't believe that someone could improve on the speed of MRI by a factor of 50X, simply because he somehow felt that everything about Ruby must be advanced in every possible way.
Scott Adams should sell cards that read: "Congratulations, you've just exhibited a prime example of PHB logic!"
Got a citation / reference for this?
http://fukamachi.org/wp/2008/06/02/maglev-and-the-naiivety-o...
There's also Jack Crenshaw's classic "Let's Build A Compiler": http://compilers.iecc.com/crenshaw/
Writing a compiler for a small language with minimal optimization features and an easy to understand assembly/bytecode format is actually relatively straightforward.
The details are usually what gives one project/company/etc a huge advantage over the rest and are usually the hardest to get right. The basic idea of everything isn't hard to grasp, but to create a proper modern compiler/operating system/game/etc is a ton of work not suited for everyone.
When you start to add all the translations to perform advanced optimization and those optimizations, you're talking about some very very cool stuff and it is kind of hard and I think of lot of people think of that when they think "compiler." Those simple code translators really ignore that which is the part most compiler users are really thankful for.
How did Bruce Lee say it? "It is like a finger pointing away to the moon. Do not concentrate on the finger or you will miss all that heavenly glory."
Following a language specification requires precise attention to detail, and understanding of the whole process helps a lot.
For a sufficiently complex language, writing code to manipulate the AST requires ability to hold a lot of data in your head at one time, or some really good visualizing tools.
Code-generation from AST can easily require a lot of effort, even when it is not especially difficult (and it can be difficult).
Optimization is difficult.
Error reporting is difficult.