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