class XPathParser {

    protected AxisStep parseAxisStep( TokenStream tokens ) {
        NodeTest nodeTest = null;
        if (tokens.canConsume('@')) {
            // Abbreviated forward step with an attribute...
            nodeTest = new AttributeNameTest(parseNameTest(tokens));
        } else if (tokens.matches('*')) {
            // Abbreviated forward step with an wildcard element ...
            nodeTest = parseNodeTest(tokens);

        } else if (tokens.matches("child", ":", ":") || tokens.matches("attribute", ":", ":") || tokens.matches("self", ":", ":")
                   || tokens.matches("descendant", ":", ":") || tokens.matches("descendant-or-self", ":", ":")
                   || tokens.matches("following-sibling", ":", ":") || tokens.matches("following", ":", ":")
                   || tokens.matches("namespace", ":", ":")) {
            // No non-abbreviated forward steps allowed
            throw new ParsingException(
                                       tokens.nextPosition(),
                                       "XPath non-abbreviated forward steps (e.g., 'child::', 'attribute::', 'self::', 'descendant::', 'descendant-or-self::', 'following-sibling::', 'following::', or 'namespace::') are not supported");
        } else if (tokens.matches("..")) {
            // No abbreviated reverse steps allowed ...
            throw new ParsingException(tokens.nextPosition(), "XPath abbreviated reverse steps (e.g., '..') are not supported");
        } else if (tokens.matches("parent", ":", ":") || tokens.matches("ancestor-or-self", ":", ":")
                   || tokens.matches("preceding-sibling", ":", ":") || tokens.matches("preceding", ":", ":")
                   || tokens.matches("ancestor", ":", ":")) {
            // No non-abbreviated reverse steps allowed ...
            throw new ParsingException(
                                       tokens.nextPosition(),
                                       "XPath non-abbreviated reverse steps (e.g., 'parent::', 'ancestor::', 'ancestor-or-self::', 'preceding-or-sibling::', or 'preceding::') are not supported");
        } else if (tokens.matches(ANY_VALUE, ":", ANY_VALUE)
                   && tokens.matches(XPathTokenizer.NAME, XPathTokenizer.SYMBOL, XPathTokenizer.NAME)) {
            // This is probably a forward step with a (qualified) name test ...
            nodeTest = parseQName(tokens);
        } else if (tokens.matches(XPathTokenizer.NAME)) {
            // This is probably a forward step with an unqualified name test ...
            nodeTest = parseNodeTest(tokens);
        } else {
            return null;
        }

        // Parse the predicates
        List<Component> predicates = parsePredicates(tokens);
        return new AxisStep(nodeTest, predicates);
    }

    public  XPathParser( TypeSystem context );

}