renjipanicker
Joined 15 years ago
Joined 15 years ago
But "tolerant" isn't the same as "as good as hand-written." A hand-rolled recursive descent parser can say something like "missing semicolon after return statement" because the code knows exactly what construct it's in.
A generated parser's error is usually derived mechanically from the state machine, "expected one of: X, Y, Z, got W", which is correct but generic. This is what Yantra does at the moment. Closing that specific gap would mostly require hand-authored, context-specific messages layered on top. But its a good problem to solve.
For yantra specifically, it doesn't have error recovery at all yet. A syntax or lexer error just stops parsing at that point, no resynchronization, no continuing to find more errors in one pass. It's a known, documented gap, not something I'd claim is solved. For the kind of smaller or evolving DSLs this is aimed at, that's probably an acceptable tradeoff, but it does exist as a limitation.
One thing worth separating out though: recursive descent is already top-down, so it gets "build the tree, then decide what to do with it" for free, the same way ANTLR's LL(*) does. The intresting part of what I built is that it's getting that capability while keeping LALR's bottom-up table-driven parsing.
Where a grammar-first tool like this is more useful is smaller or evolving DSLs, where you want the grammar as a readable, declarative spec with automatic conflict detection instead of hand-tuned lookahead logic, and cases like generating multiple outputs (e.g. C++ and Java) from one grammar, which is awkward to bolt onto a hand-rolled parser after the fact.
But as you said, it's still one linear left-to-right pass. Appreciate you drawing the line precisely.
To a large extent, it depends on the target platform. If you developing an application to work across the widest possible range of desktop and mobile platforms, C++ is your best bet.
Using C++, you can have a single code base that can be compiled for Windows, OSX, Linux, iOS, Android and WinMo. There is no other language that gives you that.
The UI code is not portable in any case, but that would be a common problem regardless of language.
One clarification on the "low-level speed from Python" part though: I think the more useful path there isn't a separate Python code-generator (which would mean Python itself doing the AST walking, probably giving up most of that speed), but Python bindings over the generated C++ classes, something like pybind11 or nanobind wrapping the AST and walker types. That gets you both: parse and walk at C++ speed, call it from Python. A true Python backend would be a different, slower thing aimed at a different use case (prototyping grammars without a C++ toolchain, say).
No promises on timeline, but if there's real interest I'd probably go the bindings route first.