public static final class Parser.Reference<T> extends AtomicReference<Parser<T>>
Parser
used in recursive grammars.
For example, the following is a recursive grammar for a simple calculator:
Terminals terms = Terminals.operators("(", ")", "+", "-");
Parser.Reference<Integer> ref = Parser.newReference();
Parser<Integer> literal = Terminals.IntegerLiteral.PARSER.map(new Function<String, Integer>() {
...
return Integer.parseInt(s);
});
Parser.Reference<Integer> parenthesized = // recursion in rule E = (E)
Parsers.between(terms.token("("), ref.lazy(), terms.token(")"));
ref.set(new OperatorTable()
.infixl(terms.token("+").retn(plus), 10)
.infixl(terms.token("-").retn(minus), 10)
.build(literal.or(parenthesized)));
return ref.get();
Note that a left recursive grammar will result in StackOverflowError
.
Use appropriate parser built-in parser combinators to avoid left-recursion.
For instance, many left recursive grammar rules can be thought as logically equivalent to
postfix operator rules. In such case, either OperatorTable
or Parser.postfix(org.jparsec.Parser<? extends java.util.function.Function<? super T, ? extends T>>)
can be used to work around left recursion.
The following is a left recursive parser for array types in the form of "T[]" or "T[][]":
Terminals terms = Terminals.operators("[", "]");
Parser.Reference<Type> ref = Parser.newReference();
ref.set(Parsers.or(leafTypeParser,
Parsers.sequence(ref.lazy(), terms.phrase("[", "]"), new Unary<Type>() {...})));
return ref.get();
And it will fail. A correct implementation is:
Terminals terms = Terminals.operators("[", "]");
return leafTypeParer.postfix(terms.phrase("[", "]").retn(new Unary<Type>() {...}));
A not-so-obvious example, is to parse the expr ? a : b
ternary operator. It too is a
left recursive grammar. And un-intuitively it can also be thought as a postfix operator.
Basically, we can parse "? a : b" as a whole into a unary operator that accepts the condition
expression as input and outputs the full ternary expression:
Parser<Expr> ternary(Parser<Expr> expr) {
return expr.postfix(
Parsers.sequence(
terms.token("?"), expr, terms.token(":"), expr,
(unused, then, unused, orelse) -> cond ->
new TernaryExpr(cond, then, orelse)));
}
Constructor and Description |
---|
Reference() |
Modifier and Type | Method and Description |
---|---|
Parser<T> |
lazy()
A
Parser that delegates to the parser object referenced by this during parsing time. |
accumulateAndGet, compareAndSet, get, getAndAccumulate, getAndSet, getAndUpdate, lazySet, set, toString, updateAndGet, weakCompareAndSet
Copyright © 2013–2016 jparsec. All rights reserved.