blob: 37e2d060e2e5f672d5e35f91efc223835aa23a84 [file] [log] [blame]
/*
* [The "BSD licence"]
* Copyright (c) 2005-2008 Terence Parr
* All rights reserved.
*
* Conversion to C#:
* Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace Antlr.Runtime
{
using ConditionalAttribute = System.Diagnostics.ConditionalAttribute;
using Console = System.Console;
using IDebugEventListener = Antlr.Runtime.Debug.IDebugEventListener;
public delegate int SpecialStateTransitionHandler( DFA dfa, int s, IIntStream input );
/** <summary>A DFA implemented as a set of transition tables.</summary>
*
* <remarks>
* Any state that has a semantic predicate edge is special; those states
* are generated with if-then-else structures in a specialStateTransition()
* which is generated by cyclicDFA template.
*
* There are at most 32767 states (16-bit signed short).
* Could get away with byte sometimes but would have to generate different
* types and the simulation code too. For a point of reference, the Java
* lexer's Tokens rule DFA has 326 states roughly.
* </remarks>
*/
public class DFA
{
protected short[] eot;
protected short[] eof;
protected char[] min;
protected char[] max;
protected short[] accept;
protected short[] special;
protected short[][] transition;
protected int decisionNumber;
/** <summary>Which recognizer encloses this DFA? Needed to check backtracking</summary> */
protected BaseRecognizer recognizer;
public readonly bool debug = false;
public DFA()
: this( new SpecialStateTransitionHandler( SpecialStateTransitionDefault ) )
{
}
public DFA( SpecialStateTransitionHandler specialStateTransition )
{
this.SpecialStateTransition = specialStateTransition ?? new SpecialStateTransitionHandler( SpecialStateTransitionDefault );
}
public virtual string Description
{
get
{
return "n/a";
}
}
/** <summary>
* 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.
* </summary>
*/
public virtual int Predict( IIntStream input )
{
if ( debug )
{
Console.Error.WriteLine( "Enter DFA.predict for decision " + decisionNumber );
}
int mark = input.Mark(); // remember where decision started in input
int s = 0; // we always start at s0
try
{
for ( ; ; )
{
if ( debug )
Console.Error.WriteLine( "DFA " + decisionNumber + " state " + s + " LA(1)=" + (char)input.LA( 1 ) + "(" + input.LA( 1 ) +
"), index=" + input.Index );
int specialState = special[s];
if ( specialState >= 0 )
{
if ( debug )
{
Console.Error.WriteLine( "DFA " + decisionNumber +
" state " + s + " is special state " + specialState );
}
s = SpecialStateTransition( this, specialState, input );
if ( debug )
{
Console.Error.WriteLine( "DFA " + decisionNumber +
" returns from special state " + specialState + " to " + s );
}
if ( s == -1 )
{
NoViableAlt( s, input );
return 0;
}
input.Consume();
continue;
}
if ( accept[s] >= 1 )
{
if ( debug )
Console.Error.WriteLine( "accept; predict " + accept[s] + " from state " + s );
return accept[s];
}
// look for a normal char transition
char c = (char)input.LA( 1 ); // -1 == \uFFFF, all tokens fit in 65000 space
if ( c >= min[s] && c <= max[s] )
{
int snext = transition[s][c - min[s]]; // move to next state
if ( snext < 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 ( eot[s] >= 0 )
{ // EOT Transition to accept state?
if ( debug )
Console.Error.WriteLine( "EOT transition" );
s = 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?
continue;
}
NoViableAlt( s, input );
return 0;
}
s = snext;
input.Consume();
continue;
}
if ( eot[s] >= 0 )
{ // EOT Transition?
if ( debug )
Console.Error.WriteLine( "EOT transition" );
s = eot[s];
input.Consume();
continue;
}
if ( c == unchecked( (char)TokenTypes.EndOfFile ) && eof[s] >= 0 )
{ // EOF Transition to accept state?
if ( debug )
Console.Error.WriteLine( "accept via EOF; predict " + accept[eof[s]] + " from " + eof[s] );
return accept[eof[s]];
}
// not in range and not EOF/EOT, must be invalid symbol
if ( debug )
{
Console.Error.WriteLine( "min[" + s + "]=" + min[s] );
Console.Error.WriteLine( "max[" + s + "]=" + max[s] );
Console.Error.WriteLine( "eot[" + s + "]=" + eot[s] );
Console.Error.WriteLine( "eof[" + s + "]=" + eof[s] );
for ( int p = 0; p < transition[s].Length; p++ )
{
Console.Error.Write( transition[s][p] + " " );
}
Console.Error.WriteLine();
}
NoViableAlt( s, input );
return 0;
}
}
finally
{
input.Rewind( mark );
}
}
protected virtual void NoViableAlt( int s, IIntStream input )
{
if ( recognizer.state.backtracking > 0 )
{
recognizer.state.failed = true;
return;
}
NoViableAltException nvae =
new NoViableAltException( Description,
decisionNumber,
s,
input );
Error( nvae );
throw nvae;
}
/** <summary>A hook for debugging interface</summary> */
public virtual void Error( NoViableAltException nvae )
{
}
public SpecialStateTransitionHandler SpecialStateTransition
{
get;
private set;
}
//public virtual int specialStateTransition( int s, IntStream input )
//{
// return -1;
//}
static int SpecialStateTransitionDefault( DFA dfa, int s, IIntStream input )
{
return -1;
}
/** <summary>
* 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. :(
* </summary>
*/
public static short[] UnpackEncodedString( string encodedString )
{
// walk first to find how big it is.
int size = 0;
for ( int i = 0; i < encodedString.Length; i += 2 )
{
size += encodedString[i];
}
short[] data = new short[size];
int di = 0;
for ( int i = 0; i < encodedString.Length; i += 2 )
{
char n = encodedString[i];
char v = encodedString[i + 1];
// add v n times to data
for ( int j = 1; j <= n; j++ )
{
data[di++] = (short)v;
}
}
return data;
}
/** <summary>Hideous duplication of code, but I need different typed arrays out :(</summary> */
public static char[] UnpackEncodedStringToUnsignedChars( string encodedString )
{
// walk first to find how big it is.
int size = 0;
for ( int i = 0; i < encodedString.Length; i += 2 )
{
size += encodedString[i];
}
char[] data = new char[size];
int di = 0;
for ( int i = 0; i < encodedString.Length; i += 2 )
{
char n = encodedString[i];
char v = encodedString[i + 1];
// add v n times to data
for ( int j = 1; j <= n; j++ )
{
data[di++] = v;
}
}
return data;
}
[Conditional("ANTLR_DEBUG")]
protected virtual void DebugRecognitionException(RecognitionException ex)
{
IDebugEventListener dbg = recognizer.DebugListener;
if (dbg != null)
dbg.RecognitionException(ex);
}
}
}