public XPathElement[] split(String path) {
		ANTLRInputStream in;
		try {
			in = new ANTLRInputStream(new StringReader(path));
		}
		catch (IOException ioe) {
			throw new IllegalArgumentException("Could not read path: "+path, ioe);
		}
		XPathLexer lexer = new XPathLexer(in) {
			@Override
			public void recover(LexerNoViableAltException e) { throw e;	}
		};
		lexer.removeErrorListeners();
		lexer.addErrorListener(new XPathLexerErrorListener());
		CommonTokenStream tokenStream = new CommonTokenStream(lexer);
		try {
			tokenStream.fill();
		}
		catch (LexerNoViableAltException e) {
			int pos = lexer.getCharPositionInLine();
			String msg = "Invalid tokens or characters at index "+pos+" in path '"+path+"'";
			throw new IllegalArgumentException(msg, e);
		}

		List<Token> tokens = tokenStream.getTokens();
//		System.out.println("path="+path+"=>"+tokens);
		List<XPathElement> elements = new ArrayList<XPathElement>();
		int n = tokens.size();
		int i=0;
loop:
		while ( i<n ) {
			Token el = tokens.get(i);
			Token next = null;
			switch ( el.getType() ) {
				case XPathLexer.ROOT :
				case XPathLexer.ANYWHERE :
					boolean anywhere = el.getType() == XPathLexer.ANYWHERE;
					i++;
					next = tokens.get(i);
					boolean invert = next.getType()==XPathLexer.BANG;
					if ( invert ) {
						i++;
						next = tokens.get(i);
					}
					XPathElement pathElement = getXPathElement(next, anywhere);
					pathElement.invert = invert;
					elements.add(pathElement);
					i++;
					break;

				case XPathLexer.TOKEN_REF :
				case XPathLexer.RULE_REF :
				case XPathLexer.WILDCARD :
					elements.add( getXPathElement(el, false) );
					i++;
					break;

				case Token.EOF :
					break loop;

				default :
					throw new IllegalArgumentException("Unknowth path element "+el);
			}
		}
		return elements.toArray(new XPathElement[0]);
	}
Represent a subset of XPath XML path syntax for use in identifying nodes in
parse trees.

<p>
Split path into words and separators {@code /} and {@code //} via ANTLR
itself then walk path elements from left to right. At each separator-word
pair, find set of nodes. Next stage uses those as work list.</p>

<p>
The basic interface is
{@link XPath#findAll ParseTree.findAll}{@code (tree, pathString, parser)}.
But that is just shorthand for:</p>

<pre>
{@link XPath} p = new {@link XPath#XPath XPath}(parser, pathString);
return p.{@link #evaluate evaluate}(tree);
</pre>

<p>
See {@code org.antlr.v4.test.TestXPath} for descriptions. In short, this
allows operators:</p>

<dl>
<dt>/</dt> <dd>root</dd>
<dt>//</dt> <dd>anywhere</dd>
<dt>!</dt> <dd>invert; this must appear directly after root or anywhere
operator</dd>
</dl>

<p>
and path elements:</p>

<dl>
<dt>ID</dt> <dd>token name</dd>
<dt>'string'</dt> <dd>any string literal token from the grammar</dd>
<dt>expr</dt> <dd>rule name</dd>
<dt>*</dt> <dd>wildcard matching any node</dd>
</dl>

<p>
Whitespace is not allowed.</p>
runtime/Java/src/org/antlr/v4/runtime/tree/xpath/XPath.java