2020 with 777 points: https://news.ycombinator.com/item?id=22788738
2024 with 607 points: https://news.ycombinator.com/item?id=40950235
Hacky solution for PEG such as adding a context stack requires careful management of the entry/exit point, but the more fundamental problem is that you still can't "switch" syntax, or you have to add all possible syntax combination depending on the numbers of such stacks. I believe persistent data structure and transactional data structure would help but I just couldn't find a formalism for that.
Make your parser call back into your lexer, so it can pass state to it; make the set of type names available to it.
I know it's no solace to you, but Rust and Go don't even have this problem Afaik, and it's avoidable by careful consideration.
A * B;
Which either represents a multiplication or a pointer of type A* to B, depending what the symbol table looks like. That means parsing C is impossible without these hacks, and you need to basically parse the whole file to build up this information.
A lot text editors which only support grammars can't parse this properly, there are a ton of buggy C parsers in the wild.
The issues that led to this were completely avoidable, and many languages like Pascal (which was more or less its contemporary), Go or Rust did avoid them. They don't lead to the language being more powerful or expressive.
Calling it the 'worst' might be hyperbole, but given how influential C-style syntax has become, and how much C code is out there, these issue have affected a ton of other languages downstream.
Just to give this context a little bit more substance, Pascal was designed to work on a mainframe which could address up to 4MB of RAM, with a typical setup of around 1MB (it's actually not the real amounts: the CDC-6600 the values are 128Kwords, but it had 60 bits word). These machine were beasts designed for scientific computation.
The first C compiler was implemented on a PDP-11, which could handle up to 64KB of RAM, and had 16bits words.
I assume that these constraints had a heavy influence on how each language was designed and implemented.
Note that I wasn't aware of all these details before writing this comment, I had to check.
See: http://pascal.hansotten.com/niklaus-wirth/zurich-pascal-comp...
Regarding the C compiler, it is likely that the first version was written in assembly language, which was later "translated" to C.
An early version of the compiler can be found there: https://github.com/theunafraid/first_c_compiler and does look like assembly hand converted to (early) C.
Link: https://app.codecrafters.io/courses/interpreter/overview
although I keep getting lost somewhere in the mountain :)
I also recommend munificent's other book about game programming patterns. Both are fun to read.
But that's only for books I don't want to keep, and Crafting Interpreters is definitely a keeper...
Here are is a new LUA interpreter implemented in Python:
https://github.com/rhulha/MoonPie
And here is a new language:
Probably also because there 100+ implementations for it to copy from
https://craftinginterpreters.com/representing-code.html#work...
> The style of interpretation it uses—walking the AST directly—is good enough for some real-world uses, but leaves a lot to be desired for a general-purpose scripting language.
Sometimes it's useful to teach progressively, using techniques that were used more often and aren't as much anymore, rather than firehosing a low-level bytecode at people.
[1] https://craftinginterpreters.com/a-bytecode-virtual-machine....
He's doesn't actually build on this though, but rather goes back to a single pass compiler (no AST, no visitor) for his bytecode compiler.
grug very elated find big brain developer Bob Nystrom redeem the big brain tribe and write excellent book on recursive descent: Crafting Interpreters
book available online free, but grug highly recommend all interested grugs purchase book on general principle, provide much big brain advice and grug love book very much except visitor pattern (trap!)
Grug says bad.
In all seriousness, the rough argument is that it's a "big brain" way of thinking. It sounds great on paper, but is often times not the easiest machinery to have to manage when there are simpler options (e.g. just add a method).
Grug doesn't elaborate much, but here's the author's take in slightly more detail.
What do you have against this pattern? Or what is a better alternative?
It needs to get "closed enum" lang. feature.
Ofc you can use this feature wrong and abuse default case, but in general this is very good since it prevents you about missing places to add handling and screams at you at comp time instead of runtimr
[0] https://blog.bracha.org/primordialsoup.html?snapshot=Amplefo... [1]https://newspeaklanguage.org [2]https://blog.bracha.org/primordialsoup.html?snapshot=Amplefo...
I hope we get to see "Add a type checker to Lox" sequel
And perhaps this for those leaning towards C: