XML::Filter::Dispatcher::Parser - Parses the XPath subset used by ...::Dispatcher


XML-Filter-Dispatcher documentation Contained in the XML-Filter-Dispatcher distribution.

Index


Code Index:

Top

XML::Filter::Dispatcher::Parser - Parses the XPath subset used by ...::Dispatcher

SYNOPSIS

Top

   use XML::Filter::Dispatcher::Parser;

   my $result = XML::Filter::Dispatcher::Parser->parse( $xpath );

DESCRIPTION

Top

Some notes on the parsing and evaluation:


XML-Filter-Dispatcher documentation Contained in the XML-Filter-Dispatcher distribution.

####################################################################
#
#    This file was generated using Parse::Yapp version 1.05.
#
#        Don't edit this file, use source file instead.
#
#             ANY CHANGE MADE HERE WILL BE LOST !
#
####################################################################
package XML::Filter::Dispatcher::Parser;
use vars qw ( @ISA );
use strict;

@ISA= qw ( Parse::Yapp::Driver );
#Included Parse/Yapp/Driver.pm file----------------------------------------
{
#
# Module Parse::Yapp::Driver
#
# This module is part of the Parse::Yapp package available on your
# nearest CPAN
#
# Any use of this module in a standalone parser make the included
# text under the same copyright as the Parse::Yapp module itself.
#
# This notice should remain unchanged.
#
# (c) Copyright 1998-2001 Francois Desarmenien, all rights reserved.
# (see the pod text in Parse::Yapp module for use and distribution rights)
#

package Parse::Yapp::Driver;

require 5.004;

use strict;

use vars qw ( $VERSION $COMPATIBLE $FILENAME );

$VERSION = '1.05';
$COMPATIBLE = '0.07';
$FILENAME=__FILE__;

use Carp;

#Known parameters, all starting with YY (leading YY will be discarded)
my(%params)=(YYLEX => 'CODE', 'YYERROR' => 'CODE', YYVERSION => '',
			 YYRULES => 'ARRAY', YYSTATES => 'ARRAY', YYDEBUG => '');
#Mandatory parameters
my(@params)=('LEX','RULES','STATES');

sub new {
    my($class)=shift;
	my($errst,$nberr,$token,$value,$check,$dotpos);
    my($self)={ ERROR => \&_Error,
				ERRST => \$errst,
                NBERR => \$nberr,
				TOKEN => \$token,
				VALUE => \$value,
				DOTPOS => \$dotpos,
				STACK => [],
				DEBUG => 0,
				CHECK => \$check };

	_CheckParams( [], \%params, \@_, $self );

		exists($$self{VERSION})
	and	$$self{VERSION} < $COMPATIBLE
	and	croak "Yapp driver version $VERSION ".
			  "incompatible with version $$self{VERSION}:\n".
			  "Please recompile parser module.";

        ref($class)
    and $class=ref($class);

    bless($self,$class);
}

sub YYParse {
    my($self)=shift;
    my($retval);

	_CheckParams( \@params, \%params, \@_, $self );

	if($$self{DEBUG}) {
		_DBLoad();
		$retval = eval '$self->_DBParse()';#Do not create stab entry on compile
        $@ and die $@;
	}
	else {
		$retval = $self->_Parse();
	}
    $retval
}

sub YYData {
	my($self)=shift;

		exists($$self{USER})
	or	$$self{USER}={};

	$$self{USER};
	
}

sub YYErrok {
	my($self)=shift;

	${$$self{ERRST}}=0;
    undef;
}

sub YYNberr {
	my($self)=shift;

	${$$self{NBERR}};
}

sub YYRecovering {
	my($self)=shift;

	${$$self{ERRST}} != 0;
}

sub YYAbort {
	my($self)=shift;

	${$$self{CHECK}}='ABORT';
    undef;
}

sub YYAccept {
	my($self)=shift;

	${$$self{CHECK}}='ACCEPT';
    undef;
}

sub YYError {
	my($self)=shift;

	${$$self{CHECK}}='ERROR';
    undef;
}

sub YYSemval {
	my($self)=shift;
	my($index)= $_[0] - ${$$self{DOTPOS}} - 1;

		$index < 0
	and	-$index <= @{$$self{STACK}}
	and	return $$self{STACK}[$index][1];

	undef;	#Invalid index
}

sub YYCurtok {
	my($self)=shift;

        @_
    and ${$$self{TOKEN}}=$_[0];
    ${$$self{TOKEN}};
}

sub YYCurval {
	my($self)=shift;

        @_
    and ${$$self{VALUE}}=$_[0];
    ${$$self{VALUE}};
}

sub YYExpect {
    my($self)=shift;

    keys %{$self->{STATES}[$self->{STACK}[-1][0]]{ACTIONS}}
}

sub YYLexer {
    my($self)=shift;

	$$self{LEX};
}


#################
# Private stuff #
#################


sub _CheckParams {
	my($mandatory,$checklist,$inarray,$outhash)=@_;
	my($prm,$value);
	my($prmlst)={};

	while(($prm,$value)=splice(@$inarray,0,2)) {
        $prm=uc($prm);
			exists($$checklist{$prm})
		or	croak("Unknow parameter '$prm'");
			ref($value) eq $$checklist{$prm}
		or	croak("Invalid value for parameter '$prm'");
        $prm=unpack('@2A*',$prm);
		$$outhash{$prm}=$value;
	}
	for (@$mandatory) {
			exists($$outhash{$_})
		or	croak("Missing mandatory parameter '".lc($_)."'");
	}
}

sub _Error {
	print "Parse error.\n";
}

sub _DBLoad {
	{
		no strict 'refs';

			exists(${__PACKAGE__.'::'}{_DBParse})#Already loaded ?
		and	return;
	}
	my($fname)=__FILE__;
	my(@drv);
	open(DRV,"<$fname") or die "Report this as a BUG: Cannot open $fname";
	while(<DRV>) {
                	/^\s*sub\s+_Parse\s*{\s*$/ .. /^\s*}\s*#\s*_Parse\s*$/
        	and     do {
                	s/^#DBG>//;
                	push(@drv,$_);
        	}
	}
	close(DRV);

	$drv[0]=~s/_P/_DBP/;
	eval join('',@drv);
}

#Note that for loading debugging version of the driver,
#this file will be parsed from 'sub _Parse' up to '}#_Parse' inclusive.
#So, DO NOT remove comment at end of sub !!!
sub _Parse {
    my($self)=shift;

	my($rules,$states,$lex,$error)
     = @$self{ 'RULES', 'STATES', 'LEX', 'ERROR' };
	my($errstatus,$nberror,$token,$value,$stack,$check,$dotpos)
     = @$self{ 'ERRST', 'NBERR', 'TOKEN', 'VALUE', 'STACK', 'CHECK', 'DOTPOS' };

#DBG>	my($debug)=$$self{DEBUG};
#DBG>	my($dbgerror)=0;

#DBG>	my($ShowCurToken) = sub {
#DBG>		my($tok)='>';
#DBG>		for (split('',$$token)) {
#DBG>			$tok.=		(ord($_) < 32 or ord($_) > 126)
#DBG>					?	sprintf('<%02X>',ord($_))
#DBG>					:	$_;
#DBG>		}
#DBG>		$tok.='<';
#DBG>	};

	$$errstatus=0;
	$$nberror=0;
	($$token,$$value)=(undef,undef);
	@$stack=( [ 0, undef ] );
	$$check='';

    while(1) {
        my($actions,$act,$stateno);

        $stateno=$$stack[-1][0];
        $actions=$$states[$stateno];

#DBG>	print STDERR ('-' x 40),"\n";
#DBG>		$debug & 0x2
#DBG>	and	print STDERR "In state $stateno:\n";
#DBG>		$debug & 0x08
#DBG>	and	print STDERR "Stack:[".
#DBG>					 join(',',map { $$_[0] } @$stack).
#DBG>					 "]\n";


        if  (exists($$actions{ACTIONS})) {

				defined($$token)
            or	do {
				($$token,$$value)=&$lex($self);
#DBG>				$debug & 0x01
#DBG>			and	print STDERR "Need token. Got ".&$ShowCurToken."\n";
			};

            $act=   exists($$actions{ACTIONS}{$$token})
                    ?   $$actions{ACTIONS}{$$token}
                    :   exists($$actions{DEFAULT})
                        ?   $$actions{DEFAULT}
                        :   undef;
        }
        else {
            $act=$$actions{DEFAULT};
#DBG>			$debug & 0x01
#DBG>		and	print STDERR "Don't need token.\n";
        }

            defined($act)
        and do {

                $act > 0
            and do {        #shift

#DBG>				$debug & 0x04
#DBG>			and	print STDERR "Shift and go to state $act.\n";

					$$errstatus
				and	do {
					--$$errstatus;

#DBG>					$debug & 0x10
#DBG>				and	$dbgerror
#DBG>				and	$$errstatus == 0
#DBG>				and	do {
#DBG>					print STDERR "**End of Error recovery.\n";
#DBG>					$dbgerror=0;
#DBG>				};
				};


                push(@$stack,[ $act, $$value ]);

					$$token ne ''	#Don't eat the eof
				and	$$token=$$value=undef;
                next;
            };

            #reduce
            my($lhs,$len,$code,@sempar,$semval);
            ($lhs,$len,$code)=@{$$rules[-$act]};

#DBG>			$debug & 0x04
#DBG>		and	$act
#DBG>		and	print STDERR "Reduce using rule ".-$act." ($lhs,$len): ";

                $act
            or  $self->YYAccept();

            $$dotpos=$len;

                unpack('A1',$lhs) eq '@'    #In line rule
            and do {
                    $lhs =~ /^\@[0-9]+\-([0-9]+)$/
                or  die "In line rule name '$lhs' ill formed: ".
                        "report it as a BUG.\n";
                $$dotpos = $1;
            };

            @sempar =       $$dotpos
                        ?   map { $$_[1] } @$stack[ -$$dotpos .. -1 ]
                        :   ();

            $semval = $code ? &$code( $self, @sempar )
                            : @sempar ? $sempar[0] : undef;

            splice(@$stack,-$len,$len);

                $$check eq 'ACCEPT'
            and do {

#DBG>			$debug & 0x04
#DBG>		and	print STDERR "Accept.\n";

				return($semval);
			};

                $$check eq 'ABORT'
            and	do {

#DBG>			$debug & 0x04
#DBG>		and	print STDERR "Abort.\n";

				return(undef);

			};

#DBG>			$debug & 0x04
#DBG>		and	print STDERR "Back to state $$stack[-1][0], then ";

                $$check eq 'ERROR'
            or  do {
#DBG>				$debug & 0x04
#DBG>			and	print STDERR 
#DBG>				    "go to state $$states[$$stack[-1][0]]{GOTOS}{$lhs}.\n";

#DBG>				$debug & 0x10
#DBG>			and	$dbgerror
#DBG>			and	$$errstatus == 0
#DBG>			and	do {
#DBG>				print STDERR "**End of Error recovery.\n";
#DBG>				$dbgerror=0;
#DBG>			};

			    push(@$stack,
                     [ $$states[$$stack[-1][0]]{GOTOS}{$lhs}, $semval ]);
                $$check='';
                next;
            };

#DBG>			$debug & 0x04
#DBG>		and	print STDERR "Forced Error recovery.\n";

            $$check='';

        };

        #Error
            $$errstatus
        or   do {

            $$errstatus = 1;
            &$error($self);
                $$errstatus # if 0, then YYErrok has been called
            or  next;       # so continue parsing

#DBG>			$debug & 0x10
#DBG>		and	do {
#DBG>			print STDERR "**Entering Error recovery.\n";
#DBG>			++$dbgerror;
#DBG>		};

            ++$$nberror;

        };

			$$errstatus == 3	#The next token is not valid: discard it
		and	do {
				$$token eq ''	# End of input: no hope
			and	do {
#DBG>				$debug & 0x10
#DBG>			and	print STDERR "**At eof: aborting.\n";
				return(undef);
			};

#DBG>			$debug & 0x10
#DBG>		and	print STDERR "**Dicard invalid token ".&$ShowCurToken.".\n";

			$$token=$$value=undef;
		};

        $$errstatus=3;

		while(	  @$stack
			  and (		not exists($$states[$$stack[-1][0]]{ACTIONS})
			        or  not exists($$states[$$stack[-1][0]]{ACTIONS}{error})
					or	$$states[$$stack[-1][0]]{ACTIONS}{error} <= 0)) {

#DBG>			$debug & 0x10
#DBG>		and	print STDERR "**Pop state $$stack[-1][0].\n";

			pop(@$stack);
		}

			@$stack
		or	do {

#DBG>			$debug & 0x10
#DBG>		and	print STDERR "**No state left on stack: aborting.\n";

			return(undef);
		};

		#shift the error token

#DBG>			$debug & 0x10
#DBG>		and	print STDERR "**Shift \$error token and go to state ".
#DBG>						 $$states[$$stack[-1][0]]{ACTIONS}{error}.
#DBG>						 ".\n";

		push(@$stack, [ $$states[$$stack[-1][0]]{ACTIONS}{error}, undef ]);

    }

    #never reached
	croak("Error in driver logic. Please, report it as a BUG");

}#_Parse
#DO NOT remove comment

1;

}
#End of include--------------------------------------------------


#line 9 "xfdxpath.yp"

    use Carp;
    use UNIVERSAL;
    use XML::Filter::Dispatcher::Ops;

    sub _no {
        my $p = shift;
#        push @{$p->{USER}->{NONONO}}, join(
die join(
            "",
            "XPath construct not supported: ",
            join( " ", map
                defined $_
                    ? ref $_
                        ? do {
                            my $f = ref $_;
                            $f =~ s/^XFD:://;
                            $f;
                        }
                        : $_
                    : "<undef>" ,
                @_
            ),
            " (grammar rule at ",
            (caller)[1],
            ", line ",
            (caller)[2],
            ")"
        );

        return ();
    }

    sub _step {
        my @ops = grep $_, @_;

        for ( 0..$#ops-1 ) {
            $ops[$_]->set_next( $ops[$_+1] );
        }
            
        return $ops[0];
    }


sub new {
        my($class)=shift;
        ref($class)
    and $class=ref($class);

    my($self)=$class->SUPER::new( yyversion => '1.05',
                                  yystates =>
[
	{#State 0
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'and_expr' => 18,
			'absolute_location_path' => 3,
			'or_expr' => 20,
			'equality_expr' => 6,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'expr' => 13,
			'additive_expr' => 22,
			'location_path' => 14,
			'unary_expr' => 23,
			'primary_expr' => 24,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 1
		DEFAULT => -44
	},
	{#State 2
		ACTIONS => {
			'DOT_DOT' => 1,
			'DOT' => 17,
			'AT' => 7,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'step' => 12,
			'relative_location_path' => 29,
			'axis' => 10
		}
	},
	{#State 3
		DEFAULT => -35
	},
	{#State 4
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 30,
			'union_expr' => 25
		}
	},
	{#State 5
		ACTIONS => {
			'SLASH_SLASH' => 31,
			'SLASH' => 32
		},
		DEFAULT => -34
	},
	{#State 6
		ACTIONS => {
			'BANG_EQUALS' => 35,
			'EQUALS_EQUALS' => 34,
			'EQUALS' => 33
		},
		DEFAULT => -5
	},
	{#State 7
		DEFAULT => -47
	},
	{#State 8
		DEFAULT => -52
	},
	{#State 9
		DEFAULT => -27
	},
	{#State 10
		ACTIONS => {
			'TEXT' => 38,
			'NAME_COLON_STAR' => 36,
			'QNAME' => 40,
			'STAR' => 42,
			'PI' => 41,
			'COMMENT' => 37,
			'NODE' => 39
		},
		GOTOS => {
			'node_test' => 43
		}
	},
	{#State 11
		ACTIONS => {
			'NAME_COLON_STAR' => -45,
			'AT' => 7,
			'COMMENT' => -45,
			'DOT' => 17,
			'STAR' => -45,
			'AXIS_NAME' => 26,
			'DOT_DOT' => 1,
			'TEXT' => -45,
			'NODE' => -45,
			'QNAME' => -45,
			'PI' => -45
		},
		DEFAULT => -36,
		GOTOS => {
			'step' => 12,
			'relative_location_path' => 44,
			'axis' => 10
		}
	},
	{#State 12
		DEFAULT => -39
	},
	{#State 13
		ACTIONS => {
			'' => 45
		}
	},
	{#State 14
		DEFAULT => -29
	},
	{#State 15
		DEFAULT => -53
	},
	{#State 16
		ACTIONS => {
			'LPAR' => 46
		}
	},
	{#State 17
		DEFAULT => -43
	},
	{#State 18
		ACTIONS => {
			'AMP_AMP' => 47,
			'AMP' => 48,
			'AND' => 49
		},
		DEFAULT => -2
	},
	{#State 19
		DEFAULT => -50
	},
	{#State 20
		ACTIONS => {
			'VBAR_VBAR' => 50,
			'OR' => 51
		},
		DEFAULT => -1
	},
	{#State 21
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'and_expr' => 18,
			'absolute_location_path' => 3,
			'or_expr' => 20,
			'equality_expr' => 6,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'expr' => 52,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 22
		ACTIONS => {
			'MINUS' => 53,
			'PLUS' => 54
		},
		DEFAULT => -13
	},
	{#State 23
		DEFAULT => -21
	},
	{#State 24
		DEFAULT => -48,
		GOTOS => {
			'predicates' => 55
		}
	},
	{#State 25
		ACTIONS => {
			'VBAR' => 56
		},
		DEFAULT => -25
	},
	{#State 26
		ACTIONS => {
			'COLON_COLON' => 57
		}
	},
	{#State 27
		ACTIONS => {
			'MULTIPLY' => 58,
			'MOD' => 59,
			'DIV' => 60
		},
		DEFAULT => -18
	},
	{#State 28
		ACTIONS => {
			'LTE' => 63,
			'LT' => 64,
			'GTE' => 61,
			'GT' => 62
		},
		DEFAULT => -9
	},
	{#State 29
		ACTIONS => {
			'SLASH_SLASH' => 31,
			'SLASH' => 32
		},
		DEFAULT => -38
	},
	{#State 30
		DEFAULT => -26
	},
	{#State 31
		ACTIONS => {
			'DOT_DOT' => 1,
			'DOT' => 17,
			'AT' => 7,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'step' => 65,
			'axis' => 10
		}
	},
	{#State 32
		ACTIONS => {
			'DOT_DOT' => 1,
			'DOT' => 17,
			'AT' => 7,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'step' => 66,
			'axis' => 10
		}
	},
	{#State 33
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 67,
			'multiplicative_expr' => 27
		}
	},
	{#State 34
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 68,
			'multiplicative_expr' => 27
		}
	},
	{#State 35
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 69,
			'multiplicative_expr' => 27
		}
	},
	{#State 36
		DEFAULT => -61
	},
	{#State 37
		ACTIONS => {
			'LPAR' => 70
		}
	},
	{#State 38
		ACTIONS => {
			'LPAR' => 71
		}
	},
	{#State 39
		ACTIONS => {
			'LPAR' => 72
		}
	},
	{#State 40
		DEFAULT => -59
	},
	{#State 41
		ACTIONS => {
			'LPAR' => 73
		}
	},
	{#State 42
		DEFAULT => -60
	},
	{#State 43
		DEFAULT => -48,
		GOTOS => {
			'predicates' => 74
		}
	},
	{#State 44
		ACTIONS => {
			'SLASH_SLASH' => 31,
			'SLASH' => 32
		},
		DEFAULT => -37
	},
	{#State 45
		DEFAULT => 0
	},
	{#State 46
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26,
			'RPAR' => -55
		},
		DEFAULT => -45,
		GOTOS => {
			'and_expr' => 18,
			'absolute_location_path' => 3,
			'or_expr' => 20,
			'equality_expr' => 6,
			'relative_location_path' => 5,
			'args' => 75,
			'opt_args' => 77,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'expr' => 76,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 47
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'equality_expr' => 78,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 48
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'equality_expr' => 79,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 49
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'equality_expr' => 80,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 50
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'and_expr' => 81,
			'absolute_location_path' => 3,
			'equality_expr' => 6,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 51
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'and_expr' => 82,
			'absolute_location_path' => 3,
			'equality_expr' => 6,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 52
		ACTIONS => {
			'RPAR' => 83
		}
	},
	{#State 53
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'multiplicative_expr' => 84
		}
	},
	{#State 54
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'multiplicative_expr' => 85
		}
	},
	{#State 55
		ACTIONS => {
			'SLASH_SLASH' => 86,
			'SLASH' => 88,
			'LSQB' => 89
		},
		DEFAULT => -31,
		GOTOS => {
			'segment' => 87
		}
	},
	{#State 56
		ACTIONS => {
			'DOT_DOT' => 1,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'step' => 12,
			'absolute_location_path' => 3,
			'primary_expr' => 24,
			'location_path' => 14,
			'relative_location_path' => 5,
			'path_expr' => 90,
			'axis' => 10
		}
	},
	{#State 57
		DEFAULT => -46
	},
	{#State 58
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 91,
			'union_expr' => 25
		}
	},
	{#State 59
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 92,
			'union_expr' => 25
		}
	},
	{#State 60
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 93,
			'union_expr' => 25
		}
	},
	{#State 61
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 94,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'multiplicative_expr' => 27
		}
	},
	{#State 62
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 95,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'multiplicative_expr' => 27
		}
	},
	{#State 63
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 96,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'multiplicative_expr' => 27
		}
	},
	{#State 64
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'absolute_location_path' => 3,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'additive_expr' => 97,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'multiplicative_expr' => 27
		}
	},
	{#State 65
		DEFAULT => -41
	},
	{#State 66
		DEFAULT => -40
	},
	{#State 67
		ACTIONS => {
			'LTE' => 63,
			'LT' => 64,
			'GTE' => 61,
			'GT' => 62
		},
		DEFAULT => -10
	},
	{#State 68
		ACTIONS => {
			'LTE' => 63,
			'LT' => 64,
			'GTE' => 61,
			'GT' => 62
		},
		DEFAULT => -12
	},
	{#State 69
		ACTIONS => {
			'LTE' => 63,
			'LT' => 64,
			'GTE' => 61,
			'GT' => 62
		},
		DEFAULT => -11
	},
	{#State 70
		ACTIONS => {
			'RPAR' => 98
		}
	},
	{#State 71
		ACTIONS => {
			'RPAR' => 99
		}
	},
	{#State 72
		ACTIONS => {
			'RPAR' => 100
		}
	},
	{#State 73
		ACTIONS => {
			'LITERAL' => 101
		},
		DEFAULT => -66,
		GOTOS => {
			'opt_literal' => 102
		}
	},
	{#State 74
		ACTIONS => {
			'LSQB' => 89
		},
		DEFAULT => -42
	},
	{#State 75
		ACTIONS => {
			'COMMA' => 103
		},
		DEFAULT => -56
	},
	{#State 76
		DEFAULT => -57
	},
	{#State 77
		ACTIONS => {
			'RPAR' => 104
		}
	},
	{#State 78
		ACTIONS => {
			'BANG_EQUALS' => 35,
			'EQUALS_EQUALS' => 34,
			'EQUALS' => 33
		},
		DEFAULT => -7
	},
	{#State 79
		ACTIONS => {
			'BANG_EQUALS' => 35,
			'EQUALS_EQUALS' => 34,
			'EQUALS' => 33
		},
		DEFAULT => -8
	},
	{#State 80
		ACTIONS => {
			'BANG_EQUALS' => 35,
			'EQUALS_EQUALS' => 34,
			'EQUALS' => 33
		},
		DEFAULT => -6
	},
	{#State 81
		ACTIONS => {
			'AMP_AMP' => 47,
			'AMP' => 48,
			'AND' => 49
		},
		DEFAULT => -4
	},
	{#State 82
		ACTIONS => {
			'AMP_AMP' => 47,
			'AMP' => 48,
			'AND' => 49
		},
		DEFAULT => -3
	},
	{#State 83
		DEFAULT => -51
	},
	{#State 84
		ACTIONS => {
			'MULTIPLY' => 58,
			'MOD' => 59,
			'DIV' => 60
		},
		DEFAULT => -20
	},
	{#State 85
		ACTIONS => {
			'MULTIPLY' => 58,
			'MOD' => 59,
			'DIV' => 60
		},
		DEFAULT => -19
	},
	{#State 86
		ACTIONS => {
			'DOT_DOT' => 1,
			'DOT' => 17,
			'AT' => 7,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'step' => 12,
			'relative_location_path' => 105,
			'axis' => 10
		}
	},
	{#State 87
		DEFAULT => -30
	},
	{#State 88
		ACTIONS => {
			'DOT_DOT' => 1,
			'DOT' => 17,
			'AT' => 7,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'step' => 12,
			'relative_location_path' => 106,
			'axis' => 10
		}
	},
	{#State 89
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'and_expr' => 18,
			'absolute_location_path' => 3,
			'or_expr' => 20,
			'equality_expr' => 6,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'expr' => 107,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 90
		DEFAULT => -28
	},
	{#State 91
		DEFAULT => -22
	},
	{#State 92
		DEFAULT => -24
	},
	{#State 93
		DEFAULT => -23
	},
	{#State 94
		ACTIONS => {
			'MINUS' => 53,
			'PLUS' => 54
		},
		DEFAULT => -17
	},
	{#State 95
		ACTIONS => {
			'MINUS' => 53,
			'PLUS' => 54
		},
		DEFAULT => -15
	},
	{#State 96
		ACTIONS => {
			'MINUS' => 53,
			'PLUS' => 54
		},
		DEFAULT => -16
	},
	{#State 97
		ACTIONS => {
			'MINUS' => 53,
			'PLUS' => 54
		},
		DEFAULT => -14
	},
	{#State 98
		DEFAULT => -63
	},
	{#State 99
		DEFAULT => -64
	},
	{#State 100
		DEFAULT => -65
	},
	{#State 101
		DEFAULT => -67
	},
	{#State 102
		ACTIONS => {
			'RPAR' => 108
		}
	},
	{#State 103
		ACTIONS => {
			'DOT_DOT' => 1,
			'MINUS' => 4,
			'SLASH_SLASH' => 2,
			'AT' => 7,
			'LITERAL' => 8,
			'SLASH' => 11,
			'NUMBER' => 15,
			'FUNCTION_NAME' => 16,
			'DOT' => 17,
			'DOLLAR_QNAME' => 19,
			'LPAR' => 21,
			'AXIS_NAME' => 26
		},
		DEFAULT => -45,
		GOTOS => {
			'and_expr' => 18,
			'absolute_location_path' => 3,
			'or_expr' => 20,
			'equality_expr' => 6,
			'relative_location_path' => 5,
			'path_expr' => 9,
			'axis' => 10,
			'step' => 12,
			'expr' => 109,
			'additive_expr' => 22,
			'location_path' => 14,
			'primary_expr' => 24,
			'unary_expr' => 23,
			'union_expr' => 25,
			'relational_expr' => 28,
			'multiplicative_expr' => 27
		}
	},
	{#State 104
		DEFAULT => -54
	},
	{#State 105
		ACTIONS => {
			'SLASH_SLASH' => 31,
			'SLASH' => 32
		},
		DEFAULT => -33
	},
	{#State 106
		ACTIONS => {
			'SLASH_SLASH' => 31,
			'SLASH' => 32
		},
		DEFAULT => -32
	},
	{#State 107
		ACTIONS => {
			'RSQB' => 110
		}
	},
	{#State 108
		DEFAULT => -62
	},
	{#State 109
		DEFAULT => -58
	},
	{#State 110
		DEFAULT => -49
	}
],
                                  yyrules  =>
[
	[#Rule 0
		 '$start', 2, undef
	],
	[#Rule 1
		 'expr', 1, undef
	],
	[#Rule 2
		 'or_expr', 1, undef
	],
	[#Rule 3
		 'or_expr', 3,
sub
#line 107 "xfdxpath.yp"
{ XFD::Operator::or->new( @_[1,3] ) }
	],
	[#Rule 4
		 'or_expr', 3,
sub
#line 108 "xfdxpath.yp"
{
        die "XPath uses 'or' instead of Perl's '||'\n";
    }
	],
	[#Rule 5
		 'and_expr', 1, undef
	],
	[#Rule 6
		 'and_expr', 3,
sub
#line 115 "xfdxpath.yp"
{ XFD::Operator::and->new( @_[1,3] ) }
	],
	[#Rule 7
		 'and_expr', 3,
sub
#line 116 "xfdxpath.yp"
{
        die "XPath uses 'and' instead of Perl's '&&'\n";
    }
	],
	[#Rule 8
		 'and_expr', 3,
sub
#line 119 "xfdxpath.yp"
{
        die "XPath uses 'and' instead of Perl's '&'\n";
    }
	],
	[#Rule 9
		 'equality_expr', 1, undef
	],
	[#Rule 10
		 'equality_expr', 3,
sub
#line 126 "xfdxpath.yp"
{ XFD::relational_op equals     => @_[1,3] }
	],
	[#Rule 11
		 'equality_expr', 3,
sub
#line 127 "xfdxpath.yp"
{ XFD::relational_op not_equals => @_[1,3] }
	],
	[#Rule 12
		 'equality_expr', 3,
sub
#line 128 "xfdxpath.yp"
{ 
        die "XPath uses '=' instead of Perl's '=='\n";
    }
	],
	[#Rule 13
		 'relational_expr', 1, undef
	],
	[#Rule 14
		 'relational_expr', 3,
sub
#line 135 "xfdxpath.yp"
{ XFD::relational_op lt  => @_[1,3] }
	],
	[#Rule 15
		 'relational_expr', 3,
sub
#line 136 "xfdxpath.yp"
{ XFD::relational_op gt  => @_[1,3] }
	],
	[#Rule 16
		 'relational_expr', 3,
sub
#line 137 "xfdxpath.yp"
{ XFD::relational_op lte => @_[1,3] }
	],
	[#Rule 17
		 'relational_expr', 3,
sub
#line 138 "xfdxpath.yp"
{ XFD::relational_op gte => @_[1,3] }
	],
	[#Rule 18
		 'additive_expr', 1, undef
	],
	[#Rule 19
		 'additive_expr', 3,
sub
#line 143 "xfdxpath.yp"
{ XFD::math_op addition    => @_[1,3] }
	],
	[#Rule 20
		 'additive_expr', 3,
sub
#line 144 "xfdxpath.yp"
{ XFD::math_op subtraction => @_[1,3] }
	],
	[#Rule 21
		 'multiplicative_expr', 1, undef
	],
	[#Rule 22
		 'multiplicative_expr', 3,
sub
#line 149 "xfdxpath.yp"
{ XFD::math_op multiplication => @_[1,3] }
	],
	[#Rule 23
		 'multiplicative_expr', 3,
sub
#line 150 "xfdxpath.yp"
{ XFD::math_op division       => @_[1,3] }
	],
	[#Rule 24
		 'multiplicative_expr', 3,
sub
#line 151 "xfdxpath.yp"
{ XFD::math_op modulus        => @_[1,3] }
	],
	[#Rule 25
		 'unary_expr', 1, undef
	],
	[#Rule 26
		 'unary_expr', 2,
sub
#line 156 "xfdxpath.yp"
{ XFD::Negation->new( $_[2] ) }
	],
	[#Rule 27
		 'union_expr', 1, undef
	],
	[#Rule 28
		 'union_expr', 3,
sub
#line 161 "xfdxpath.yp"
{
        for ( $_[1], $_[3] ) {
            next if $_->can( "set_next" );
            $_ = ref $_;
            s/^XFD:://;
            die "Can't use a $_ in a union, perhaps you want || instead of |\n";
        }

        my $union;
        if ( $_[1]->isa( "XFD::union" ) ) {
            $_[1]->add( $_[3] );
            $union = $_[1];
        }
        else {
            $union = XFD::union->new( @_[1,3] )
        }
        $union;
    }
	],
	[#Rule 29
		 'path_expr', 1, undef
	],
	[#Rule 30
		 'path_expr', 3,
sub
#line 183 "xfdxpath.yp"
{
        return $_[1] unless defined $_[2] || defined $_[3];

        my $expr = $_[1];
        $expr = $expr->[0] if $expr->isa( "XFD::Parens" );

        ## TODO: Cope with nodesets passed in vars or
        ## returned from functions.
        die "node-set is required before a predicate or '/' (variables and functions returning nodesets are not (yet) supported)"
            unless $expr->isa( "XFD::PathTest" );

        $expr->set_next( $_[2] ) if defined $_[2];
        $expr->set_next( $_[3] ) if defined $_[3];
        $expr;
    }
	],
	[#Rule 31
		 'segment', 0, undef
	],
	[#Rule 32
		 'segment', 2,
sub
#line 202 "xfdxpath.yp"
{ $_[2] }
	],
	[#Rule 33
		 'segment', 2,
sub
#line 203 "xfdxpath.yp"
{
        my $op = XFD::Axis::descendant_or_self->new;
        $op->set_next( $_[2] );
        $op;
    }
	],
	[#Rule 34
		 'location_path', 1, undef
	],
	[#Rule 35
		 'location_path', 1, undef
	],
	[#Rule 36
		 'absolute_location_path', 1,
sub
#line 215 "xfdxpath.yp"
{ XFD::doc_node->new }
	],
	[#Rule 37
		 'absolute_location_path', 2,
sub
#line 216 "xfdxpath.yp"
{
        my $op = XFD::doc_node->new;
        $op->set_next( $_[2] );
        $op;
    }
	],
	[#Rule 38
		 'absolute_location_path', 2,
sub
#line 221 "xfdxpath.yp"
{ 
        ## /descendant-or-self::node()/relative_location_path
        my $op = XFD::doc_node->new;
        my $step = _step(
            XFD::Axis::descendant_or_self->new,
            XFD::EventType::node->new,
        );
        $op->set_next( $step );
        $step->set_next( $_[2] );
        $op;
    }
	],
	[#Rule 39
		 'relative_location_path', 1, undef
	],
	[#Rule 40
		 'relative_location_path', 3,
sub
#line 235 "xfdxpath.yp"
{ $_[1]->set_next( $_[3] ) ; $_[1] }
	],
	[#Rule 41
		 'relative_location_path', 3,
sub
#line 238 "xfdxpath.yp"
{
        my $step = _step(
            XFD::Axis::descendant_or_self->new,
            XFD::EventType::node->new,
        );
        $_[1]->set_next( $step );
        $step->set_next( $_[3] );
        $_[1];
    }
	],
	[#Rule 42
		 'step', 3,
sub
#line 250 "xfdxpath.yp"
{ _step( @_[1..$#_] ) }
	],
	[#Rule 43
		 'step', 1,
sub
#line 251 "xfdxpath.yp"
{ XFD::self_node->new }
	],
	[#Rule 44
		 'step', 1,
sub
#line 252 "xfdxpath.yp"
{ _no @_; }
	],
	[#Rule 45
		 'axis', 0,
sub
#line 256 "xfdxpath.yp"
{ XFD::Axis::child->new     }
	],
	[#Rule 46
		 'axis', 2,
sub
#line 257 "xfdxpath.yp"
{ XFD::axis( $_[1] )        }
	],
	[#Rule 47
		 'axis', 1,
sub
#line 258 "xfdxpath.yp"
{ XFD::Axis::attribute->new }
	],
	[#Rule 48
		 'predicates', 0, undef
	],
	[#Rule 49
		 'predicates', 4,
sub
#line 263 "xfdxpath.yp"
{
        my $p = XFD::predicate->new( $_[3] );
        if ( defined $_[1] ) {
            $_[1]->set_next( $p );
            return $_[1];
        }
        return $p;
    }
	],
	[#Rule 50
		 'primary_expr', 1,
sub
#line 274 "xfdxpath.yp"
{ XFD::VariableReference->new( $_[1] ) }
	],
	[#Rule 51
		 'primary_expr', 3,
sub
#line 275 "xfdxpath.yp"
{ XFD::Parens->new( $_[2] ) }
	],
	[#Rule 52
		 'primary_expr', 1, undef
	],
	[#Rule 53
		 'primary_expr', 1, undef
	],
	[#Rule 54
		 'primary_expr', 4,
sub
#line 278 "xfdxpath.yp"
{ XFD::function( @_[1,3] ) }
	],
	[#Rule 55
		 'opt_args', 0,
sub
#line 282 "xfdxpath.yp"
{ [] }
	],
	[#Rule 56
		 'opt_args', 1, undef
	],
	[#Rule 57
		 'args', 1,
sub
#line 287 "xfdxpath.yp"
{ [ $_[1] ] }
	],
	[#Rule 58
		 'args', 3,
sub
#line 288 "xfdxpath.yp"
{
        push @{$_[1]}, $_[3];
        $_[1];
    }
	],
	[#Rule 59
		 'node_test', 1,
sub
#line 295 "xfdxpath.yp"
{
        $XFD::dispatcher->{Namespaces}
            ? do {
                my ( $ns_uri, $local_name ) =
                    XFD::PathTest->_parse_ns_uri_and_localname( $_[1] );

                my $op = XFD::namespace_test->new( $ns_uri );
                $op->set_next(
                    XFD::node_local_name->new( $local_name )
                );
                $op;
            }
            : XFD::node_name->new( $_[1] );
    }
	],
	[#Rule 60
		 'node_test', 1,
sub
#line 309 "xfdxpath.yp"
{ XFD::EventType::principal_event_type->new; }
	],
	[#Rule 61
		 'node_test', 1,
sub
#line 310 "xfdxpath.yp"
{
        my ( $ns_uri ) = 
            XFD::PathTest->_parse_ns_uri_and_localname( $_[1] );
        XFD::namespace_test->new( $ns_uri )
    }
	],
	[#Rule 62
		 'node_test', 4,
sub
#line 315 "xfdxpath.yp"
{ XFD::EventType::processing_instruction
                                                           ->new( $_[2] ) }
	],
	[#Rule 63
		 'node_test', 3,
sub
#line 317 "xfdxpath.yp"
{ XFD::EventType::comment      ->new }
	],
	[#Rule 64
		 'node_test', 3,
sub
#line 318 "xfdxpath.yp"
{ XFD::EventType::text         ->new }
	],
	[#Rule 65
		 'node_test', 3,
sub
#line 319 "xfdxpath.yp"
{ XFD::EventType::node         ->new }
	],
	[#Rule 66
		 'opt_literal', 0, undef
	],
	[#Rule 67
		 'opt_literal', 1,
sub
#line 324 "xfdxpath.yp"
{ _no @_; }
	]
],
                                  @_);
    bless($self,$class);
}

#line 327 "xfdxpath.yp"


use Carp;

my %tokens = (qw(
    .           DOT
    ..          DOT_DOT
    @           AT
    *           STAR
    (           LPAR
    )           RPAR
    [           LSQB
    ]           RSQB
    ::          COLON_COLON
    /           SLASH
    //          SLASH_SLASH
    |           VBAR
    +           PLUS
    -           MINUS
    =           EQUALS
    !=          BANG_EQUALS
    >           GT
    <           LT
    >=          GTE
    <=          LTE

    ==          EQUALS_EQUALS
    ||          VBAR_VBAR
    &&          AMP_AMP
    &           AMP
),
    "," =>      "COMMA"
);

my $simple_tokens =
    join "|",
        map
            quotemeta,
            reverse
                sort {
                    length $a <=> length $b
                } keys %tokens;

my $NCName = "(?:[a-zA-Z_][a-zA-Z0-9_.-]*)"; ## TODO: comb. chars & Extenders

my %EventType = qw(
    node                   NODE
    text                   TEXT
    comment                COMMENT
    processing-instruction PI
);

my $EventType = "(?:" .
    join( "|", map quotemeta, sort {length $a <=> length $b} keys %EventType ) .
    ")";

my $AxisName = "(?:" .  join( "|", split /\n+/, <<AXIS_LIST_END ) . ")" ;
ancestor
ancestor-or-self
attribute
child
descendant
descendant-or-self
following
following-sibling
namespace
parent
preceding
preceding-sibling
self
end
AXIS_LIST_END

my %preceding_tokens = map { ( $_ => undef ) } ( qw(
    @ :: [
    and or mod div
    *
    / // | + - = != < <= > >=

    == & && ||
    ),
    "(", ","
) ;


sub debugging () { 0 }


sub lex {
    my ( $p ) = @_;

    ## Optimization notes: we aren't parsing War and Peace here, so
    ## readability over performance.

    my $d = $p->{USER};
    my $input = \$d->{Input};

    ## This needs to be more contextual, only recognizing axis/function-name
    if ( ( pos( $$input ) || 0 ) == length $$input ) {
        $d->{LastToken} = undef;
        return ( '', undef );
    }

    my ( $token, $val ) ;
    ## First do the disambiguation rules:

    ## If there is a preceding token and the preceding token is not
    ## one of "@", "::", "(", "[", "," or an Operator,
    if ( defined $d->{LastToken}
        && ! exists $preceding_tokens{$d->{LastToken}}
    ) {
        ## a * must be recognized as a MultiplyOperator
        if ( $$input =~ /\G\s*\*/gc ) {
            ( $token, $val ) = ( MULTIPLY => "*" );
        }
        ## an NCName must be recognized as an OperatorName.
        elsif ( $$input =~ /\G\s*($NCName)/gc ) {
            die "Expected and, or, mod or div, got '$1'\n"
                unless 0 <= index "and|or|mod|div", $1;
            ( $token, $val ) = ( uc $1, $1 );
        }
    }

    ## NOTE: \s is only an approximation for ExprWhitespace
    unless ( defined $token ) {
        $$input =~ m{\G\s*(?:
                        ## If the character following an NCName (possibly after
                        ## intervening ExprWhitespace) is (, then the token must be
                        ## recognized as a EventType or a FunctionName.
                        ($NCName)\s*(?=\()

                        ## If the two characters following an NCName (possibly after
                        ## intervening ExprWhitespace) are ::, then the token must be
                        ## recognized as an AxisName
                        |($NCName)\s*(?=::)

                        ## Otherwise, it's just a normal lexer.
                        |($NCName:\*)                           #NAME_COLON_STAR
                        |((?:$NCName:)?$NCName)                 #QNAME
                        |('[^']*'|"[^"]*")                      #LITERAL
                        |(-?\d+(?:\.\d+)?|\.\d+)                #NUMBER
                        |\$((?:$NCName:)?$NCName)               #DOLLAR_QNAME
                        |($simple_tokens)
                )\s*}gcx;

        ( $token, $val ) =
            defined $1  ? (
                exists $EventType{$1}
                    ? ( $EventType{$1}, $1 )
                    : ( FUNCTION_NAME => $1 )
            ) :
        
            defined $2 ? ( AXIS_NAME        =>  $2 ) :
            defined $3 ? ( NAME_COLON_STAR  =>  $3 ) :
            defined $4 ? ( QNAME            =>  $4 ) :
            defined $5 ? ( LITERAL          =>  do {
                    my $s = substr( $5, 1, -1 );
                    $s =~ s/([\\'])/\\$1/g;
                    XFD::StringConstant->new( $s );
                }
            ) :
            defined $6 ? ( NUMBER           =>
                XFD::NumericConstant->new( "$6")
            ) :
            defined $7 ? ( DOLLAR_QNAME     =>  $7 ) :
            defined $8 ? ( $tokens{$8}      =>  $8 ) :
            die "Failed to parse '$$input' at ",
                pos $$input,
                "\n";
    }

    $d->{LastToken} = $val;

    if ( debugging ) {
        warn
            "'",
            $$input,
            "' (",
            pos $$input,
            "):",
            join( " => ", map defined $_ ? $_ : "<undef>", $token, $val ),
            "\n";
    }

    return ( $token, $val );
}


sub error {
    my ( $p ) = @_;
    print "Couldn't parse '$p->{USER}->{Input}' at position ", pos $p->{USER}->{Input}, "\n";
}

## _parse is an internal, reentrant entry point; it's used to parse rules
## and subrules.
sub _parse {
    my $self = shift;
    my ( $expr, $action_code ) = @_;

    my $options = $XFD::dispatcher;

    warn "Parsing '$expr'\n" if $options->{Debug};

    my $p = XML::Filter::Dispatcher::Parser->new(
        yylex   => \&lex,
        yyerror => \&error,
        ( $options->{Debug} || 0 ) > 5
            ? ( yydebug => 0x1D )
            : (),
    );

    %{$p->{USER}} = %$options if $options;
    $p->{USER}->{Input} = $expr;
    local $XFD::dispatcher->{ParseNestingDepth}
        = $XFD::dispatcher->{ParseNestingDepth} + 1;

    my $op_tree = eval {
        $p->YYParse;                ## <== the actual parse
    };

    die $@ if $@;

    die map "$_\n", @{$p->{USER}->{NONONO}}
        if $p->{USER}->{NONONO} ;

    return undef unless defined $op_tree;

    die "grammar returned '$op_tree', needed a ref\n"
        unless ref $op_tree;

    ## TODO: figure a way to allow a limited subset
    ## of EventPath patterns, kinda like allowing
    ## a pattern match against the generated Op tree,
    ## or alternate grammar files.  The former could
    ## give more helpful error messages, the latter
    ## could be more flexible because it would allow
    ## non-standard grammars.
    $op_tree = XFD::ExprEval->new( $op_tree )
        unless $op_tree->isa( "XFD::PathTest" );

    $op_tree->set_next( XFD::action( $action_code ) );

    return $op_tree;
}


sub parse {
    my $self = shift;
    local $XFD::dispatcher = shift;
    my ( $expr, $context ) = @_;

    $XFD::dispatcher->{ParseNestingDepth} = 0;
    $XFD::dispatcher->{OpTree} ||= XFD::union->new;

    my $op_tree = $self->_parse( @_ );

    my $rule = XFD::Rule->new( $expr );
    $rule->set_next( $op_tree );
    $XFD::dispatcher->{OpTree}->add( $rule );
}

1 ;

1;