| // [The "BSD licence"] |
| // Copyright (c) 2006-2007 Kay Roepke 2010 Alan Condit |
| // 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. |
| |
| |
| #import "ANTLRStringStream.h" |
| |
| extern NSInteger debug; |
| |
| @implementation ANTLRStringStream |
| |
| @synthesize data; |
| @synthesize n; |
| @synthesize index; |
| @synthesize line; |
| @synthesize charPositionInLine; |
| @synthesize markDepth; |
| @synthesize markers; |
| @synthesize lastMarker; |
| @synthesize name; |
| @synthesize charState; |
| |
| + newANTLRStringStream |
| { |
| return [[ANTLRStringStream alloc] init]; |
| } |
| |
| + newANTLRStringStream:(NSString *)aString; |
| { |
| return [[ANTLRStringStream alloc] initWithString:aString]; |
| } |
| |
| |
| + newANTLRStringStream:(char *)myData Count:(NSInteger)numBytes; |
| { |
| return [[ANTLRStringStream alloc] initWithData:myData Count:numBytes]; |
| } |
| |
| |
| - (id) init |
| { |
| if ((self = [super init]) != nil) { |
| n = 0; |
| index = 0; |
| line = 1; |
| charPositionInLine = 0; |
| markDepth = 0; |
| markers = [ANTLRPtrBuffer newANTLRPtrBufferWithLen:10]; |
| [markers retain]; |
| [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based, |
| charState = [[ANTLRCharStreamState newANTLRCharStreamState] retain]; |
| } |
| return self; |
| } |
| |
| - (id) initWithString:(NSString *) theString |
| { |
| if ((self = [super init]) != nil) { |
| //[self setData:[NSString stringWithString:theString]]; |
| data = [theString retain]; |
| n = [data length]; |
| index = 0; |
| line = 1; |
| charPositionInLine = 0; |
| markDepth = 0; |
| markers = [[ANTLRPtrBuffer newANTLRPtrBufferWithLen:10] retain]; |
| [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based, |
| charState = [[ANTLRCharStreamState newANTLRCharStreamState] retain]; |
| } |
| return self; |
| } |
| |
| - (id) initWithStringNoCopy:(NSString *) theString |
| { |
| if ((self = [super init]) != nil) { |
| //[self setData:theString]; |
| data = [theString retain]; |
| n = [data length]; |
| index = 0; |
| line = 1; |
| charPositionInLine = 0; |
| markDepth = 0; |
| markers = [ANTLRPtrBuffer newANTLRPtrBufferWithLen:100]; |
| [markers retain]; |
| [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based, |
| charState = [[ANTLRCharStreamState newANTLRCharStreamState] retain]; |
| } |
| return self; |
| } |
| |
| - (id) initWithData:(char *)myData Count:(NSInteger)numBytes |
| { |
| if ((self = [super init]) != nil) { |
| data = [NSString stringWithCString:myData encoding:NSASCIIStringEncoding]; |
| n = numBytes; |
| index = 0; |
| line = 1; |
| charPositionInLine = 0; |
| markDepth = 0; |
| markers = [ANTLRPtrBuffer newANTLRPtrBufferWithLen:100]; |
| [markers retain]; |
| [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based, |
| charState = [[ANTLRCharStreamState newANTLRCharStreamState] retain]; |
| } |
| return( self ); |
| } |
| |
| - (void) dealloc |
| { |
| #ifdef DEBUG_DEALLOC |
| NSLog( @"called dealloc in ANTLRStringStream" ); |
| #endif |
| if ( markers && [markers count] ) { |
| [markers removeAllObjects]; |
| [markers release]; |
| markers = nil; |
| } |
| if ( data ) { |
| [data release]; |
| data = nil; |
| } |
| [super dealloc]; |
| } |
| |
| - (id) copyWithZone:(NSZone *)aZone |
| { |
| ANTLRStringStream *copy; |
| |
| copy = [[[self class] allocWithZone:aZone] init]; |
| // copy = [super copyWithZone:aZone]; // allocation occurs here |
| if ( data != nil ) |
| copy.data = [self.data copyWithZone:aZone]; |
| copy.n = n; |
| copy.index = index; |
| copy.line = line; |
| copy.charPositionInLine = charPositionInLine; |
| copy.markDepth = markDepth; |
| if ( markers != nil ) |
| copy.markers = [markers copyWithZone:nil]; |
| copy.lastMarker = lastMarker; |
| if ( name != nil ) |
| copy.name = [self.name copyWithZone:aZone]; |
| return copy; |
| } |
| |
| // reset the streams charState |
| // the streams content is not reset! |
| - (void) reset |
| { |
| index = 0; |
| line = 1; |
| charPositionInLine = 0; |
| markDepth = 0; |
| if ( markers && [markers count] ) |
| [markers removeAllObjects]; |
| [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based, |
| // thus the initial null in the array! |
| } |
| |
| // read one character off the stream, tracking line numbers and character positions |
| // automatically. |
| // Override this in subclasses if you want to avoid the overhead of automatic line/pos |
| // handling. Do not call super in that case. |
| - (void) consume |
| { |
| if ( index < n ) { |
| charPositionInLine++; |
| if ( [data characterAtIndex:index] == '\n' ) { |
| line++; |
| charPositionInLine=0; |
| } |
| index++; |
| } |
| } |
| |
| // implement the lookahead method used in lexers |
| - (NSInteger) LA:(NSInteger) i |
| { |
| NSInteger c; |
| if ( i == 0 ) |
| return 0; // undefined |
| if ( i < 0 ) { |
| i++; |
| if ( index+i-1 < 0 ) { |
| return ANTLRCharStreamEOF; |
| } |
| } |
| if ( (index+i-1) >= n ) { |
| return ANTLRCharStreamEOF; |
| } |
| c = [data characterAtIndex:index+i-1]; |
| return (NSInteger)c; |
| } |
| |
| - (NSInteger) LT:(NSInteger)i |
| { |
| return [self LA:i]; |
| } |
| |
| - (NSInteger) size |
| { |
| return n; |
| } |
| |
| // push the current charState of the stream onto a stack |
| // returns the depth of the stack, to be used as a marker to rewind the stream. |
| // Note: markers are 1-based! |
| - (NSInteger) mark |
| { |
| if (debug > 1) NSLog(@"mark entry -- markers=%x, markDepth=%d\n", (int)markers, markDepth); |
| if ( markers == nil ) { |
| markers = [ANTLRPtrBuffer newANTLRPtrBufferWithLen:100]; |
| [markers addObject:[NSNull null]]; // ANTLR generates code that assumes markers to be 1-based, |
| markDepth = markers.ptr; |
| } |
| markDepth++; |
| ANTLRCharStreamState *State = nil; |
| if ( (markDepth) >= [markers count] ) { |
| if ( markDepth > 1 ) { |
| State = [ANTLRCharStreamState newANTLRCharStreamState]; |
| [State retain]; |
| } |
| if ( markDepth == 1 ) |
| State = charState; |
| [markers insertObject:State atIndex:markDepth]; |
| if (debug > 1) NSLog(@"mark save State %x at %d, index=%d, line=%d, charPositionInLine=%d\n", (NSUInteger)State, markDepth, State.index, State.line, State.charPositionInLine); |
| } |
| else { |
| if (debug > 1) NSLog(@"mark retrieve markers=%x markDepth=%d\n", (NSUInteger)markers, markDepth); |
| State = [markers objectAtIndex:markDepth]; |
| [State retain]; |
| State = (ANTLRCharStreamState *)[markers objectAtIndex:markDepth]; |
| if (debug > 1) NSLog(@"mark retrieve charState %x from %d, index=%d, line=%d, charPositionInLine=%d\n", (NSUInteger)State, markDepth, State.index, State.line, State.charPositionInLine); |
| } |
| State.index = index; |
| State.line = line; |
| State.charPositionInLine = charPositionInLine; |
| lastMarker = markDepth; |
| if (debug > 1) NSLog(@"mark exit -- markers=%x, charState=%x, index=%d, line=%d, charPositionInLine=%d\n", (NSUInteger)markers, (NSUInteger)State, State.index, State.line, State.charPositionInLine); |
| return markDepth; |
| } |
| |
| - (void) rewind:(NSInteger) marker |
| { |
| ANTLRCharStreamState *State; |
| if (debug > 1) NSLog(@"rewind entry -- markers=%x marker=%d\n", (NSUInteger)markers, marker); |
| if ( marker == 1 ) |
| State = charState; |
| else |
| State = (ANTLRCharStreamState *)[markers objectAtIndex:marker]; |
| if (debug > 1) NSLog(@"rewind entry -- marker=%d charState=%x, index=%d, line=%d, charPositionInLine=%d\n", marker, (NSUInteger)charState, charState.index, charState.line, charState.charPositionInLine); |
| // restore stream charState |
| [self seek:State.index]; |
| line = State.line; |
| charPositionInLine = charState.charPositionInLine; |
| [self release:marker]; |
| if (debug > 1) NSLog(@"rewind exit -- marker=%d charState=%x, index=%d, line=%d, charPositionInLine=%d\n", marker, (NSUInteger)charState, charState.index, charState.line, charState.charPositionInLine); |
| } |
| |
| - (void) rewind |
| { |
| [self rewind:lastMarker]; |
| } |
| |
| // remove stream states on top of 'marker' from the marker stack |
| // returns the new markDepth of the stack. |
| // Note: unfortunate naming for Objective-C, but to keep close to the Java target this is named release: |
| - (void) release:(NSInteger) marker |
| { |
| // unwind any other markers made after marker and release marker |
| markDepth = marker; |
| markDepth--; |
| if (debug > 1) NSLog(@"release:marker= %d, markDepth = %d\n", marker, markDepth); |
| } |
| |
| // when seeking forward we must handle character position and line numbers. |
| // seeking backward already has the correct line information on the markers stack, |
| // so we just take it from there. |
| - (void) seek:(NSInteger) anIndex |
| { |
| if (debug > 1) NSLog(@"seek entry -- seekIndex=%d index=%d\n", anIndex, index); |
| if ( anIndex <= index ) { |
| index = anIndex; // just jump; don't update stream charState (line, ...) |
| if (debug > 1) NSLog(@"seek exit return -- index=%d index=%d\n", anIndex, index); |
| return; |
| } |
| // seek forward, consume until index hits anIndex |
| while ( index < anIndex ) { |
| [self consume]; |
| } |
| if (debug > 1) NSLog(@"seek exit end -- index=%d index=%d\n", anIndex, index); |
| } |
| |
| // get a substring from our raw data. |
| - (NSString *) substring:(NSInteger)startIndex To:(NSInteger)stopIndex |
| { |
| NSRange theRange = NSMakeRange(startIndex, stopIndex-startIndex); |
| return [data substringWithRange:theRange]; |
| } |
| |
| // get a substring from our raw data. |
| - (NSString *) substringWithRange:(NSRange) theRange |
| { |
| return [data substringWithRange:theRange]; |
| } |
| |
| |
| - (ANTLRPtrBuffer *)getMarkers |
| { |
| return markers; |
| } |
| |
| - (void) setMarkers:(ANTLRPtrBuffer *)aMarkerList |
| { |
| markers = aMarkerList; |
| } |
| |
| - (NSString *)getSourceName |
| { |
| return name; |
| } |
| |
| - (void) setSourceName:(NSString *)aName |
| { |
| if ( name != aName ) { |
| if ( name ) [name release]; |
| if ( aName ) [aName retain]; |
| name = aName; |
| } |
| } |
| |
| |
| - (ANTLRCharStreamState *)getCharState |
| { |
| return charState; |
| } |
| |
| - (void) setCharState:(ANTLRCharStreamState *)aCharState |
| { |
| charState = aCharState; |
| } |
| |
| - (NSString *)toString |
| { |
| return [NSString stringWithString:data]; |
| } |
| |
| //---------------------------------------------------------- |
| // data |
| //---------------------------------------------------------- |
| - (NSString *) getData |
| { |
| return data; |
| } |
| |
| - (void) setData: (NSString *) aData |
| { |
| if (data != aData) { |
| if ( data ) [data release]; |
| data = [NSString stringWithString:aData]; |
| [data retain]; |
| } |
| } |
| |
| @end |