bd82
* https://github.com/antlr/antlr4/blob/master/doc/faq/general....
* See: "What do you think are the problems people will try to solve with ANTLR4?" question
I've used several different parser generators in the past. But I've also transitioned to hand-rolled recursive decent parsers, being Lazy I've created a library to assist in hand-rolling a recursive decent parser: https://github.com/SAP/chevrotain
- Antlr (https://github.com/antlr/antlr4/blob/master/doc/javascript-target.md)
- PegJS (https://github.com/pegjs/pegjs)
- Nearley (https://github.com/kach/nearley)Maybe it makes sense if you assume the input has already been tokenized so you are not expected to deal with the minutiae of string literal escape sequences and such and can focus on the high level design/flow...
Chevrotain - https://github.com/SAP/chevrotain
The list of features can be found here: - https://sap.github.io/chevrotain/docs/features/blazing_fast....
What is interesting imho is that Chevrotain is not a Parser Generator nor a Parser Combinator. It is a tool that makes it easier to craft hand built recursive decent parsers rather than a whole new level of abstraction.
1.The builds are much faster now. 2. The configuration has virtually no hacks anymore as I'm using Circle-CI own docker images (including browsers). 3. And the UI/UX is superior as well.
Chevrotain is an LL(K) Parser library, or more precisely SLL(K), It looks up-to K fixed token ahead to choose the next alternative.
Because it is just a library to assist in hand crafting recursive decent parsers, the same limitations apply, left recursion would lead to an infinite loop...,however left recursion is detected during initialization and an descriptive error is thrown instead.
Right recursion is allowed.
It is possible to resolve more complex ambiguities using back tracking: http://sap.github.io/chevrotain/docs/features/backtracking.h... or other types of custom logic.
However in general, the library does not try to be able to parse all the possible grammars in the world, instead the focus is more on performance, features and ease of development.
Instead of using an abstraction of a declarative grammar definition and code generation to provide an alternative to writing a parser by hand, Chevrotain simplifies the process of hand crafting a parser.
Meaning no code generation and you can still directly debug the code you have written (unlike most parser combinators).
The base performance however very low, as in two orders of magnitude lower than most other parsing libraries in JavaScript.
See benchmark at: https://sap.github.io/chevrotain/performance/ that I have created.
This is Not exactly a parser generator but an internal JavaScript DSL for writing parsers, but it does meet the criteria for a more verbose syntax.
It is implemented using a parsing library so the lookaheads are automatically performed by the library, but the general pattern is still relevant.
Basically each binary precedence level gets a rule (weakest first) and each of these rules will consume as many operators of the current precedence level as it can.
Show HN: Chevrotain – Parser Building Toolkit for JavaScript
Chevrotain – Fault-Tolerant Parser Building Toolkit for JavaScript
Chevrotain – Parser Building Toolkit for JavaScript
For example it takes 15 seconds to parse lodash.js with Ohm (on my machine) using the sample EcmaScript grammar. But what happens if my IDE has 200 files and 400KLOC of code?
From my personal experience, if you want high performance you have to treat it as an ongoing feature, this could mean:
* Inspect each new version for performance regressions.
* Reinspect previous feature implementations for possible
performance optimizations.
* keep track of underlying performance characteristics of your
runtime, for example V8 hidden class changes and other
de-optimization causes. These characteristics may (and do!)
change over time with newer releases of V8...
It would be interesting to try and optimize Ohm.js
I even contributed some optimizations to Nearley.js in the past. But I'm afraid I just don't know when I will get around to trying this with too many projects and ideas competing for my time. :(How does this relate to a discussion on the relevance of parser generators / libraries?
"In my experience, almost no one uses parser generators to build commercial compilers."
https://github.com/antlr/antlr4/blob/master/doc/faq/general..... (no anchors for direct link).
It is still possible to embed semantics inside an Antlr4 grammar.
For example see the Antlr4 EcmaScript grammar sample: https://github.com/antlr/grammars-v4/tree/master/ecmascript which uses embedded code to solve the RegExp vs division operator ambiguity.
Another scenario when embedding code could be preferred is optimizing for maximum performance as abstractions normally come at a performance overhead.
I do agree that the default approach should be to separate the semantics unless there is a very good reason why not to...
In hand crafted parsers this error recovery may be added manually (but resulting in a-lot of work...) For example: search for the word "recovery" in the TypeScript parser which is used to provide Language Services for the VSCode IDE. https://github.com/Microsoft/TypeScript/blob/master/src/comp...
Automatic Error Recovery using heuristics can also be implemented by parsing Libraries. In the world of JavaScript I'm familiar with two libraries that support Error Recovery:
Antlr4 - https://github.com/antlr/antlr4
Chevrotain - https://github.com/SAP/chevrotain (disclaimer - I'm the author of Chevrotain)
Specifically:
1. The separation of Grammar and Semantics.
2. Handling left recursion in a top down (peg) parser.
3. Incremental parsing.
I think that the one feature missing to make it applicable
for more than rapid prototyping and teaching purposes is
performance.In this benchmark I've authored: http://sap.github.io/chevrotain/performance/ Which uses the simple JSON grammar it is about two orders of magnitudes slower than most other parsing libraries in JavaScript.
So I am sure there is a great deal of room for optimizations.
I do agree that grammar validations and ambiguity detection is very important, but even if the semantics of a PEG grammar define that the first matching alternative should be taken, should it be possible to detect some cases such as unreachable alternatives as long as the grammar is structure is known in advance?
But as far as I know Esprima does not: https://github.com/jquery/esprima/issues/1168
I have no idea about Cherow...
But please consider that performance is not the only factor when building parsers.
Extensibility is a major concern. Afaik Babylon (used in babel) is a fork of Acorn partly driven by the need for greater extensibility. https://github.com/babel/babylon
Another example is espree used in ESLint https://github.com/eslint/espree According to their readme.md espree was based on Esprima and is now using Acorn. Specifically for extensibility reasons. https://github.com/eslint/espree/issues/200
Show HN: JavaScript Parsing Libraries Benchmark
Show HN: JavaScript Parsing Libraries Benchmark
Chevrotain shares two main ideas/concepts with Ohm.
1. Separation of grammar and semantics, but in a less opinionated manner as it does not enforce the separation as Ohm does (it is still possible to embed actions directly in the grammar).
2. Grammar Inheritance.
Although while those ideas are not common they are also not that rare (For example the same concepts exist in Antlr). I think there are three big conceptual differences.
1. In Chevrotain Performance is considered as a major feature. Which results in it being two orders of magnitude faster (in the benchmark linked above)
2. Chevrotain attempts to provides capabilities relevant for writing IDEs, for example automatic error recovery/tolerance and syntactic content assist.
3. Internal vs External DSL -
From an implementation perspective there is a vast difference as Ohm is an external DSL while Chevrotain is an internal DSL. In practical(user) terms this means that you can place a breakpoint directly in a Chevrotain grammar, but you cannot do so in Ohm. Or that you will need a separate editor to edit an Ohm grammar while you can use any JavaScript editor to create a Chevrotain grammar.
It also means that Ohm could be ported to different target runtimes (Like Antlr actually is) while Chevrotain can only run in an ECMAScript engine.
In programing languages which do not have true macros The combinator API normally creates a data structure representing the grammar which is than interpreted Which usually makes debugging harder and the parsing slower.