package ANTLR::Runtime::DFA; use Params::Validate qw( :types ); use Error qw( try finally ); use Moose; has 'eot' => ( is => 'rw', isa => 'ArrayRef[Int]', ); has 'eof' => ( is => 'rw', isa => 'ArrayRef[Int]', ); has 'min' => ( is => 'rw', isa => 'ArrayRef[Str]', ); has 'max' => ( is => 'rw', isa => 'ArrayRef[Str]', ); has 'accept' => ( is => 'rw', isa => 'ArrayRef[Int]', ); has 'special' => ( is => 'rw', isa => 'ArrayRef[Int]', ); has 'transition' => ( is => 'rw', isa => 'ArrayRef[ArrayRef[Int]]', ); has 'decision_number' => ( is => 'rw', isa => 'Int', ); # Which recognizer encloses this DFA? Needed to check backtracking has 'recognizer' => ( is => 'rw', isa => 'ANTLR::Runtime::BaseRecognizer', ); sub get_description { return "n/a"; } # From the input stream, predict what alternative will succeed # using this DFA (representing the covering regular approximation # to the underlying CFL). Return an alternative number 1..n. Throw # an exception upon error. sub predict { my ($self, $input) = @_; my $mark = $input->mark(); # remember where decision started in input my $s = 0; # we always start at s0 try { while (1) { my $special_state = $self->special->[$s]; if ($special_state >= 0) { $s = $self->special_state_transition($special_state, $input); if ($s == -1) { $self->no_viable_alt($s, $input); return 0; } $input->consume(); next; } if ($self->accept->[$s] >= 1) { return $self->accept->[$s]; } # look for a normal char transition my $c = $input->LA(1); # -1 == \uFFFF, all tokens fit in 65000 space if ($c >= $self->min->[$s] && $c <= $self->max->[$s]) { my $next_s = $self->transition->[$s][$c - $self->min->[$s]]; # move to next state if ($next_s < 0) { # was in range but not a normal transition # must check EOT, which is like the else clause. # eot[s]>=0 indicates that an EOT edge goes to another # state. if ($self->eot->[$s] >= 0) { # EOT Transition to accept state? $s = $self->eot->[$s]; $input->consume(); # TODO: I had this as return accept[eot[s]] # which assumed here that the EOT edge always #went to an accept...faster to do this, but # what about predicated edges coming from EOT # target? next; } $self->no_viable_alt($s, $input); return 0; } $s = $next_s; $input->consume(); next; } if ($self->eot->[$s] >= 0) { # EOT Transition? $s = $self->eot->[$s]; $input->consume(); next; } if ($c == ANTLR::Runtime::Token->EOF && $self->eof->[$s] >= 0) { # EOF Transition to accept state? return $self->accept->[$self->eof->[$s]]; } # not in range and not EOF/EOT, must be invalid symbol $self->no_viable_alt($s, $input); return 0; } } finally { $input->rewind(); }; } sub no_viable_alt { my ($self, $s, $input) = @_; if ($self->recognizer->state->backtracking > 0) { $self->recognizer->state->failed = 1; return; } my $nvae = ANTLR::Runtime::NoViableAltException({ grammar_decision_description => $self->get_description(), decision_number => $self->decision_number, state_number => $self->state_number, input => $input }); $self->error($nvae); $nvae->throw(); } # A hook for debugging interface sub error { my ($self, $nvae) = @_; } sub special_state_transition { my ($self, $s, $input) = @_; return -1; } # Given a String that has a run-length-encoding of some unsigned shorts # like "\1\2\3\9", convert to short[] {2,9,9,9}. We do this to avoid # static short[] which generates so much init code that the class won't # compile. :( sub unpack_encoded_string { my ($self, $encoded_string) = @_; my $data = []; while ($encoded_string =~ /(.)(.)/gxms) { my ($n, $v) = ($1, $2); push @$data, $v x $n; } return $data; } sub unpack_encoded_string_to_unsigned_chars { my ($self, $encoded_string) = @_; return $self->unpack_encoded_string($encoded_string); } no Moose; __PACKAGE__->meta->make_immutable(); 1; __END__