-
Notifications
You must be signed in to change notification settings - Fork 12
Design considerations
One of the fundamental differences between grappa and other parser packages, such as ANTLR and JavaCC, is that grammars (what grappa called parsers) are in pure Java; there is no DSL (Domain Specific Language) other than the ones you create via the name of your rule methods (if that can be considered a DSL at all).
The way grappa works (basically, it creates a subclass of your parser class, or classes, see below) does imply some limitations, which will be expressed first because they are important to keep in mind. On the other hand, the fact that this is Java means you have all Java at your disposal; as such, you need not think "grammar" when writing parsers. Some consequences of which are expressed below.
The rules are the following:
- your parser classes cannot be
final
; inner parser classes cannot beprivate
; - your rule methods cannot be
private
orfinal
; - methods you wish to use as boolean expressions in rules cannot be
private
(but they can befinal
); - instance variables you wish to use in rules cannot be
private
(but they can befinal
).
The reason is that when you create a parser, what you obtain is a subclass of your original parser. See here for more details.
Parsers are Java classes; you can inherit them, and even use other parsers in parsers. Do not hesitate to split!
This works fine, for instance:
public class OuterParser
extends EventBusParser<Object>
{
protected final InnerParser inner
= Parboiled.createParser(InnerParser.class);
Rule myRule()
{
return sequence("foo", inner.someRule());
}
}
Basically, don't write a 100.000 lines grammar; there's no point! If you have a whole programming language to parse, for instance, you can make one parser for a variable, another for literal values etc etc, and use them in one "main" parser.
Here again, do not hesitate; methods can take arguments, they can have variables, etc etc. The only rule to a rule method is that it must return a Rule
.
They can even make calls to other methods returning booleans in rules themselves. For instance:
public class IntParser
extends EventBusParser<Object>
{
Rule anInt()
{
return sequence(
sequence(optional('-'), oneOrMore(digit())),
isInt(match())
);
}
/*
* Reminder: cannot be private since it is used in a rule method!
*/
protected final boolean isInt(final String match)
{
try {
Integer.parseInt(match);
return true;
} catch (NumberFormatException ignored) {
return false;
}
}
}
Grappa depends on Guava. This is by design. Some people think that this library is "heavy" in that the size of the jar is over 2 MiB.
But what is 2 MiB today? And especially, what is 2 MiB when you have all the power of this library at your disposal?