// // MPTokenStream.m // MathPad // // Created by Kim Wittenburg on 20.09.14. // Copyright (c) 2014 Kim Wittenburg. All rights reserved. // #import "MPTokenStream.h" #import "MPToken.h" @implementation MPTokenStream { NSUInteger _currentTokenIndex; NSUInteger eofLocation; BOOL *whitespaceIgnores; NSUInteger maxWhitespaceIgnores; NSUInteger currentWhitespaceState; } - (instancetype)initWithTokens:(NSArray *)tokens { self = [super init]; if (self) { self.tokens = tokens; whitespaceIgnores = malloc(10 * sizeof(BOOL)); maxWhitespaceIgnores = 10; currentWhitespaceState = 0; [self beginAcceptingWhitespaceTokens]; _currentTokenIndex = 0; if (tokens.count > 0) { eofLocation = NSMaxRange([tokens.lastObject range]); } else { eofLocation = 0; } } return self; } - (void)beginAcceptingWhitespaceTokens { [self pushWhitespaceState:YES]; } - (void)beginIgnoringWhitespaceTokens { [self pushWhitespaceState:NO]; } - (void)pushWhitespaceState:(BOOL)state { currentWhitespaceState++; if (currentWhitespaceState >= maxWhitespaceIgnores) { maxWhitespaceIgnores += 10; BOOL *reallocatedWhitespaceIgnores = realloc(whitespaceIgnores, maxWhitespaceIgnores); if (reallocatedWhitespaceIgnores) { whitespaceIgnores = reallocatedWhitespaceIgnores; } else { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Realloc Failed" userInfo:nil]; } } whitespaceIgnores[currentWhitespaceState] = state; } - (void)endIgnoringOrAcceptingWhitespaceTokens { currentWhitespaceState--; } - (void)skipWhitespaces { if (whitespaceIgnores[currentWhitespaceState]) { return; } while (_currentTokenIndex < self.tokens.count) { MPToken *token = self.tokens[_currentTokenIndex]; if (token.tokenType != MPWhitespaceToken) { return; } [self currentTokenConsumed]; } } - (BOOL)hasMoreTokens { [self skipWhitespaces]; return _currentTokenIndex < self.tokens.count; } - (id)currentToken { [self skipWhitespaces]; if (_currentTokenIndex >= _tokens.count) { return [[MPToken alloc] initEOFTokenAtLocation:eofLocation]; } return _tokens[_currentTokenIndex]; } - (id)peekNextToken { NSUInteger currentTokenIndex = _currentTokenIndex; [self currentTokenConsumed]; // Pretend the current token has been consumed id token = [self currentToken]; _currentTokenIndex = currentTokenIndex; // Undo the lookahead return token; } - (void)currentTokenConsumed { [self currentToken]; ++_currentTokenIndex; } - (void)dealloc { free(whitespaceIgnores); } @end