Home | History | Annotate | Download | only in Runtime
      1 package ANTLR::Runtime::DFA;
      2 
      3 use Params::Validate qw( :types );
      4 use Error qw( try finally );
      5 
      6 use Moose;
      7 
      8 has 'eot' => (
      9     is  => 'rw',
     10     isa => 'ArrayRef[Int]',
     11 );
     12 
     13 has 'eof' => (
     14     is  => 'rw',
     15     isa => 'ArrayRef[Int]',
     16 );
     17 
     18 has 'min' => (
     19     is  => 'rw',
     20     isa => 'ArrayRef[Str]',
     21 );
     22 
     23 has 'max' => (
     24     is  => 'rw',
     25     isa => 'ArrayRef[Str]',
     26 );
     27 
     28 has 'accept' => (
     29     is  => 'rw',
     30     isa => 'ArrayRef[Int]',
     31 );
     32 
     33 has 'special' => (
     34     is  => 'rw',
     35     isa => 'ArrayRef[Int]',
     36 );
     37 
     38 has 'transition' => (
     39     is  => 'rw',
     40     isa => 'ArrayRef[ArrayRef[Int]]',
     41 );
     42 
     43 has 'decision_number' => (
     44     is  => 'rw',
     45     isa => 'Int',
     46 );
     47 
     48 
     49 # Which recognizer encloses this DFA?  Needed to check backtracking
     50 has 'recognizer' => (
     51     is  => 'rw',
     52     isa => 'ANTLR::Runtime::BaseRecognizer',
     53 );
     54 
     55 
     56 sub get_description {
     57     return "n/a";
     58 }
     59 
     60 # From the input stream, predict what alternative will succeed
     61 # using this DFA (representing the covering regular approximation
     62 # to the underlying CFL).  Return an alternative number 1..n.  Throw
     63 # an exception upon error.
     64 sub predict {
     65     my ($self, $input) = @_;
     66 
     67     my $mark = $input->mark();  # remember where decision started in input
     68     my $s = 0; # we always start at s0
     69 
     70     try {
     71         while (1) {
     72             my $special_state = $self->special->[$s];
     73             if ($special_state >= 0) {
     74                 $s = $self->special_state_transition($special_state, $input);
     75                 if ($s == -1) {
     76                     $self->no_viable_alt($s, $input);
     77                     return 0;
     78                 }
     79                 $input->consume();
     80                 next;
     81             }
     82 
     83             if ($self->accept->[$s] >= 1) {
     84                 return $self->accept->[$s];
     85             }
     86 
     87 	    # look for a normal char transition
     88             my $c = $input->LA(1);  # -1 == \uFFFF, all tokens fit in 65000 space
     89 
     90             if ($c >= $self->min->[$s] && $c <= $self->max->[$s]) {
     91                 my $next_s = $self->transition->[$s][$c - $self->min->[$s]];  # move to next state
     92 
     93                 if ($next_s < 0) {
     94                     # was in range but not a normal transition
     95                     # must check EOT, which is like the else clause.
     96                     # eot[s]>=0 indicates that an EOT edge goes to another
     97                     # state.
     98                     if ($self->eot->[$s] >= 0) {  # EOT Transition to accept state?
     99                         $s = $self->eot->[$s];
    100                         $input->consume();
    101                         # TODO: I had this as return accept[eot[s]]
    102                         # which assumed here that the EOT edge always
    103                         #went to an accept...faster to do this, but
    104                         # what about predicated edges coming from EOT
    105                         # target?
    106                         next;
    107                     }
    108 
    109                     $self->no_viable_alt($s, $input);
    110                     return 0;
    111                 }
    112 
    113                 $s = $next_s;
    114                 $input->consume();
    115                 next;
    116             }
    117 
    118 	    if ($self->eot->[$s] >= 0) {  # EOT Transition?
    119 		$s = $self->eot->[$s];
    120 		$input->consume();
    121 		next;
    122 	    }
    123 
    124 	    if ($c == ANTLR::Runtime::Token->EOF && $self->eof->[$s] >= 0) {  # EOF Transition to accept state?
    125 		return $self->accept->[$self->eof->[$s]];
    126 	    }
    127 
    128 	    # not in range and not EOF/EOT, must be invalid symbol
    129 	    $self->no_viable_alt($s, $input);
    130 	    return 0;
    131         }
    132     }
    133     finally {
    134 	$input->rewind();
    135     };
    136 }
    137 
    138 sub no_viable_alt {
    139     my ($self, $s, $input) = @_;
    140 
    141     if ($self->recognizer->state->backtracking > 0) {
    142 	$self->recognizer->state->failed = 1;
    143 	return;
    144     }
    145     my $nvae = ANTLR::Runtime::NoViableAltException({
    146 	grammar_decision_description => $self->get_description(),
    147 	decision_number => $self->decision_number,
    148 	state_number => $self->state_number,
    149 	input => $input
    150     });
    151     $self->error($nvae);
    152     $nvae->throw();
    153 }
    154 
    155 # A hook for debugging interface
    156 sub error {
    157     my ($self, $nvae) = @_;
    158 }
    159 
    160 sub special_state_transition {
    161     my ($self, $s, $input) = @_;
    162 
    163     return -1;
    164 }
    165 
    166 # Given a String that has a run-length-encoding of some unsigned shorts
    167 # like "\1\2\3\9", convert to short[] {2,9,9,9}.  We do this to avoid
    168 # static short[] which generates so much init code that the class won't
    169 # compile. :(
    170 sub unpack_encoded_string {
    171     my ($self, $encoded_string) = @_;
    172 
    173     my $data = [];
    174     while ($encoded_string =~ /(.)(.)/gxms) {
    175         my ($n, $v) = ($1, $2);
    176 
    177         push @$data, $v x $n;
    178     }
    179 
    180     return $data;
    181 }
    182 
    183 sub unpack_encoded_string_to_unsigned_chars {
    184     my ($self, $encoded_string) = @_;
    185    
    186     return $self->unpack_encoded_string($encoded_string);
    187 }
    188 
    189 no Moose;
    190 __PACKAGE__->meta->make_immutable();
    191 1;
    192 __END__
    193