Home | History | Annotate | Download | only in SlimParsing
      1 /*
      2  * [The "BSD licence"]
      3  * Copyright (c) 2005-2008 Terence Parr
      4  * All rights reserved.
      5  *
      6  * Conversion to C#:
      7  * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 // #define TRACK_POSITION
     34 
     35 namespace Antlr.Runtime
     36 {
     37     using System.Collections.Generic;
     38 
     39     /** <summary>
     40      *  A pretty quick CharStream that pulls all data from an array
     41      *  directly.  Every method call counts in the lexer.  Java's
     42      *  strings aren't very good so I'm avoiding.
     43      *  </summary>
     44      */
     45     [System.Serializable]
     46     public class SlimStringStream : ICharStream
     47     {
     48         /** <summary>The data being scanned</summary> */
     49         protected string data;
     50         //protected char[] data;
     51 
     52         /** <summary>How many characters are actually in the buffer</summary> */
     53         protected int n;
     54 
     55         /** <summary>0..n-1 index into string of next char</summary> */
     56         protected int p = 0;
     57 
     58 #if TRACK_POSITION
     59         /** <summary>line number 1..n within the input</summary> */
     60         protected int line = 1;
     61 
     62         /** <summary>The index of the character relative to the beginning of the line 0..n-1</summary> */
     63         protected int charPositionInLine = 0;
     64 #endif
     65 
     66         /** <summary>tracks how deep mark() calls are nested</summary> */
     67         protected int markDepth = 0;
     68 
     69         /** <summary>
     70          *  A list of CharStreamState objects that tracks the stream state
     71          *  values line, charPositionInLine, and p that can change as you
     72          *  move through the input stream.  Indexed from 1..markDepth.
     73          *  A null is kept @ index 0.  Create upon first call to mark().
     74          *  </summary>
     75          */
     76         protected IList<CharStreamState> markers;
     77 
     78         /** <summary>Track the last mark() call result value for use in rewind().</summary> */
     79         protected int lastMarker;
     80 
     81         /** <summary>What is name or source of this char stream?</summary> */
     82         public string name;
     83 
     84         public SlimStringStream()
     85         {
     86         }
     87 
     88         /** <summary>Copy data in string to a local char array</summary> */
     89         public SlimStringStream( string input )
     90             : this( input, null )
     91         {
     92         }
     93 
     94         public SlimStringStream( string input, string sourceName )
     95             : this( input.ToCharArray(), input.Length, sourceName )
     96         {
     97         }
     98 
     99         /** <summary>This is the preferred constructor as no data is copied</summary> */
    100         public SlimStringStream( char[] data, int numberOfActualCharsInArray )
    101             : this( data, numberOfActualCharsInArray, null )
    102         {
    103         }
    104 
    105         public SlimStringStream( char[] data, int numberOfActualCharsInArray, string sourceName )
    106             : this()
    107         {
    108             //this.data = data;
    109             this.data = new string( data );
    110             this.n = numberOfActualCharsInArray;
    111             this.name = sourceName;
    112         }
    113 
    114         /** <summary>
    115          *  Return the current input symbol index 0..n where n indicates the
    116          *  last symbol has been read.  The index is the index of char to
    117          *  be returned from LA(1).
    118          *  </summary>
    119          */
    120         public int Index
    121         {
    122             get
    123             {
    124                 return p;
    125             }
    126         }
    127 #if TRACK_POSITION
    128         public int Line
    129         {
    130             get
    131             {
    132                 return line;
    133             }
    134             set
    135             {
    136                 line = value;
    137             }
    138         }
    139         public int CharPositionInLine
    140         {
    141             get
    142             {
    143                 return charPositionInLine;
    144             }
    145             set
    146             {
    147                 charPositionInLine = value;
    148             }
    149         }
    150 #else
    151         public int Line
    152         {
    153             get
    154             {
    155                 return -1;
    156             }
    157             set
    158             {
    159             }
    160         }
    161         public int CharPositionInLine
    162         {
    163             get
    164             {
    165                 return -1;
    166             }
    167             set
    168             {
    169             }
    170         }
    171 #endif
    172 
    173         /** <summary>
    174          *  Reset the stream so that it's in the same state it was
    175          *  when the object was created *except* the data array is not
    176          *  touched.
    177          *  </summary>
    178          */
    179         public void Reset()
    180         {
    181             p = 0;
    182 #if TRACK_POSITION
    183             line = 1;
    184             charPositionInLine = 0;
    185 #endif
    186             markDepth = 0;
    187         }
    188 
    189         public void Consume()
    190         {
    191             //System.out.println("prev p="+p+", c="+(char)data[p]);
    192             if ( p < n )
    193             {
    194 #if TRACK_POSITION
    195                 charPositionInLine++;
    196                 if ( data[p] == '\n' )
    197                 {
    198                     /*
    199                     System.out.println("newline char found on line: "+line+
    200                                        "@ pos="+charPositionInLine);
    201                     */
    202                     line++;
    203                     charPositionInLine = 0;
    204                 }
    205 #endif
    206                 p++;
    207                 //System.out.println("p moves to "+p+" (c='"+(char)data[p]+"')");
    208             }
    209         }
    210 
    211         public int LA( int i )
    212         {
    213             if ( i == 0 )
    214             {
    215                 return 0; // undefined
    216             }
    217             if ( i < 0 )
    218             {
    219                 i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
    220                 if ( ( p + i - 1 ) < 0 )
    221                 {
    222                     return CharStreamConstants.EndOfFile; // invalid; no char before first char
    223                 }
    224             }
    225 
    226             if ( ( p + i - 1 ) >= n )
    227             {
    228                 //System.out.println("char LA("+i+")=EOF; p="+p);
    229                 return CharStreamConstants.EndOfFile;
    230             }
    231             //System.out.println("char LA("+i+")="+(char)data[p+i-1]+"; p="+p);
    232             //System.out.println("LA("+i+"); p="+p+" n="+n+" data.length="+data.length);
    233             return data[p + i - 1];
    234         }
    235 
    236         public int LT( int i )
    237         {
    238             return LA( i );
    239         }
    240 
    241         public int Count
    242         {
    243             get
    244             {
    245                 return n;
    246             }
    247         }
    248 
    249         public int Mark()
    250         {
    251             if ( markers == null )
    252             {
    253                 markers = new List<CharStreamState>();
    254                 markers.Add( null ); // depth 0 means no backtracking, leave blank
    255             }
    256             markDepth++;
    257             CharStreamState state = null;
    258             if ( markDepth >= markers.Count )
    259             {
    260                 state = new CharStreamState();
    261                 markers.Add( state );
    262             }
    263             else
    264             {
    265                 state = markers[markDepth];
    266             }
    267             state.p = p;
    268 #if TRACK_POSITION
    269             state.line = line;
    270             state.charPositionInLine = charPositionInLine;
    271 #endif
    272             lastMarker = markDepth;
    273             return markDepth;
    274         }
    275 
    276         public void Rewind( int m )
    277         {
    278             CharStreamState state = markers[m];
    279             // restore stream state
    280             Seek( state.p );
    281 #if TRACK_POSITION
    282             line = state.line;
    283             charPositionInLine = state.charPositionInLine;
    284 #endif
    285             Release( m );
    286         }
    287 
    288         public void Rewind()
    289         {
    290             Rewind( lastMarker );
    291         }
    292 
    293         public void Release( int marker )
    294         {
    295             // unwind any other markers made after m and release m
    296             markDepth = marker;
    297             // release this marker
    298             markDepth--;
    299         }
    300 
    301         /** <summary>
    302          *  consume() ahead until p==index; can't just set p=index as we must
    303          *  update line and charPositionInLine.
    304          *  </summary>
    305          */
    306         public void Seek( int index )
    307         {
    308             if ( index <= p )
    309             {
    310                 p = index; // just jump; don't update stream state (line, ...)
    311                 return;
    312             }
    313             // seek forward, consume until p hits index
    314             while ( p < index )
    315             {
    316                 Consume();
    317             }
    318         }
    319 
    320         public string Substring( int start, int length )
    321         {
    322             return data.Substring( start, length );
    323             //return new string( data, start, stop - start + 1 );
    324         }
    325 
    326         public string SourceName
    327         {
    328             get
    329             {
    330                 return name;
    331             }
    332         }
    333     }
    334 }
    335