InstaParse: Context-Free Grammars as Easy as Regular Expressions
github.com
github.com
In Opa (http://opalang.org), we decided to have parsers as first-class objects: cf. https://github.com/MLstate/opalang/wiki/The-core-language#pa...
And this is used at least 35 times in a real project such as PEPS: https://github.com/MLstate/PEPS
(according to `git grep "= parser" | wc -l`)
Anecdotally, my experience with Scala's parser combinators has led me to the latter conclusion bu not the former. Parsers and parser generators are very specific tools which (as useful as they are) don't see use in most applications. This leads you to a situation like the one in Scala, where open source libs such as Parboiled ( http://git.io/xpg3 ) are far better than the std lib offering because they recieve more attention.
All the tests pass and it works for my use case, but it'd be great to get some more data points.
It sort of mushes together the two steps ("lexing" and "parsing"), which, as far as I can tell, are traditionally distinguished from one another.
I guess that the "token" definitions really just reside within the EBNF rules..
Its also supposed to be pretty performant, although I have never seen a side by side comparison with ANTLR and friends.
I also contributed the viz hooks, back in the day, finding it difficult to work with parsers without an antlr-style tree printer. It's a fun time to be into parsers, there's a lot going on in the space.
Try decompiling a grammar into combinators!
My knowledge of Clojure is very limited, but it appears to run on the JVM and should work. It installs via Maven just fine. Running it, however, is currently beyond my ken.
A little sample Java code would open this fine piece of software to a much wider audience.
import clojure.java.api.*;
import clojure.lang.IFn;
import clojure.lang.PersistentVector;
public class Core {
public static void main(String[] args)
{
String grammar1 = "S = AB*\n" +
"AB = A B\n" +
"A = 'a'+\n" +
"B = 'b'+";
Clojure.var("clojure.core", "require").invoke(Clojure.read("instaparse.core"));
IFn parser = Clojure.var("instaparse.core", "parser");
IFn asandbs = (IFn)parser.invoke(grammar1);
PersistentVector result = (PersistentVector)asandbs.invoke("aaaaabbbaaaabb");
System.out.println(result.get(0).toString());
}
}
But, my suggestion would be to build a Java friendly api in Clojure, with gen-class, and then consume that.People (and Wikipedia) like to pretend that e.g. PEG grammars cannot be ambiguous, because the PEG "choice" operator is ordered. In reality, that doesn't make them unambiguous, it just hides the ambiguity. By the same logic, you could say that LR grammars cannot be ambiguous either; the parser generator will always produce a working parser. The difference is, LR parser generators warn you about the parts of the grammar where the generator had to make a choice (and their choices are well-documented and not arbitrary), while PEG parsers don't.
[1] https://en.wikipedia.org/wiki/Ambiguous_grammar#Recognizing_...
Remember that ambiguity only refers to whether or not there can be multiple derivations for the same string, not whether the parser action is ambiguous. For example, consider:
S: "a" "b" "c" | A "b" "d"
A: "a"
This LR(1) grammar has a shift/reduce conflict, but it is unambiguous.You could even make it worse by:
S: "a" B "c" | A B "d"
A: "a"
B: "b" | B "b"
in which interpreting this as an LR(k) grammar for all k < ∞ results in conflicts even though the grammar is still unambiguous.1. Can it parse its input using an LR(k) grammar in time linear in its input when k > 1?
2. Is there any other parser known to be able to achieve the above in practice?
EDIT: this is still way cool in itself.
EBNF is a DSL.
I happen to like it more than many apis because of it's history, stability, and my experience with it. But, that's an opinion.
Let's not forget that string-based programming is the source of many many bugs
Since the parser generator compiles the EBNF into an executable function at runtime. The solution is the same as writing code in Ruby, JavaScript, or any other dynamic language. Write a unit test.
But Instaparse has exposed all the functionality as an "in the language" DSL as well using parser combinators in a map structure (near the bottom of the README).
You can also turn a string specification into a grammar map/combinator specification, which I have used when a part of my parser was generated at run time.
Come, let us go down and confuse their language so they will not understand each other.
Like the issue with RegEx, its probably better to use nice English words in code to describe a problem solution, so that other people can understand it faster (before they get demotivated).
The amazing thing about Regex's is that they make describing some state machines easy.
Well, most of the time, no one else needs to understand it ...
The hard part of regular expressions is envisioning the languages they accept. It's not primarily a difficulty with notation as with the concepts the notation encodes.
I see you too.. like to live dangerously. tips hat