Package org.jparsec

Class 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 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)));
   }
 
See Also:
  • Field Details

    • lazy

      private final Parser<T> lazy
  • Constructor Details

    • Reference

      public Reference()
  • Method Details

    • lazy

      public Parser<T> lazy()
      A Parser that delegates to the parser object referenced by this during parsing time.