org.codehaus.jparsec
Class Parser.Reference<T>
java.lang.Object
java.util.concurrent.atomic.AtomicReference<Parser<T>>
org.codehaus.jparsec.Parser.Reference<T>
- All Implemented Interfaces:
- Serializable
- Enclosing class:
- Parser<T>
public static final class Parser.Reference<T>
- extends AtomicReference<Parser<T>>
An atomic mutable reference to 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 Map<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.codehaus.jparsec.Parser extends org.codehaus.jparsec.functors.Map 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,
new Map4<...>() {
public Unary<Expr> map(unused, consequence, unused, alternative) {
// (condition) -> Ternary(condition, consequence, alternative)
return new Unary<Expr>() {
...
return new TernaryExpr(condition, consequence, alternative);
}
}
}));
}
- See Also:
- Serialized Form
Method Summary |
Parser<T> |
lazy()
A Parser that delegates to the parser object referenced by this during parsing time. |
Parser.Reference
public Parser.Reference()
lazy
public Parser<T> lazy()
- A
Parser
that delegates to the parser object referenced by this
during parsing time.
Copyright © 2014. All rights reserved.