Archived
1
This repository has been archived on 2022-08-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
mathpad/MathPad/MPExpressionTokenizer.m
2014-11-10 21:45:50 +01:00

148 lines
5.8 KiB
Objective-C

//
// MPExpressionLexer.m
// MathPad
//
// Created by Kim Wittenburg on 19.09.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPExpressionTokenizer.h"
#import "MPExpression.h"
#import "MPExpressionElement.h"
#import "MPToken.h"
#import "NSRegularExpression+MPParsingAdditions.h"
#define MPRangeExists(range) (range.location != NSNotFound)
@implementation MPExpressionTokenizer
+ (NSArray *)tokenizeExpression:(MPExpression *)expression
{
NSMutableArray *tokens = [[NSMutableArray alloc] init];
NSUInteger symbolIndex = 0;
for (NSUInteger index = 0; index < [expression countItemsInReferenceFrame:MPElementReferenceFrame]; index++) {
id <MPExpressionElement> element = [expression itemAtIndex:index referenceFrame:MPElementReferenceFrame];
if ([element isFunction]) {
[tokens addObject:element];
} else {
[tokens addObjectsFromArray:[self tokenizeElement:(NSString *)element
elementSymbolIndex:symbolIndex]];
}
symbolIndex += element.length;
}
return tokens;
}
+ (NSArray *)tokenizeElement:(NSString *)element
elementSymbolIndex:(NSUInteger)symbolIndex
{
NSUInteger lexLocation = 0;
NSString *decimalSeparator = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]];
NSString *regexStringFormat = @"\\A(?:"
@"([\\*∙⋅])|"
@"([+-](?:\\s*[+-])*)|"
@"((?:\\d+(?:%@\\d+)?)|(?:%@\\d+))|"
@"(sin)|"
@"(cos)|"
@"(tan)|"
@"(asin)|"
@"(acos)|"
@"(atan)|"
@"([A-Za-z])|"
@"(!)|"
@"(=)|"
@"(\\s+)"
@")";
NSString *regexString = [NSString stringWithFormat:regexStringFormat, decimalSeparator, decimalSeparator];
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexString
options:0
error:NULL];
NSMutableArray *tokens = [[NSMutableArray alloc] init];
while (lexLocation < element.length) {
NSTextCheckingResult *match = [regex firstMatchInString:element fromIndex:lexLocation];
NSRange range = NSMakeRange(lexLocation, 1);
MPTokenType tokenType = MPUnidentifiedToken;
if (match) {
NSRange multiplicationSymbolRange = [match rangeAtIndex:1];
NSRange operatorRange = [match rangeAtIndex:2];
NSRange numberRange = [match rangeAtIndex:3];
NSRange sinRange = [match rangeAtIndex:4];
NSRange cosRange = [match rangeAtIndex:5];
NSRange tanRange = [match rangeAtIndex:6];
NSRange asinRange = [match rangeAtIndex:7];
NSRange acosRange = [match rangeAtIndex:8];
NSRange atanRange = [match rangeAtIndex:9];
NSRange variableRange = [match rangeAtIndex:10];
NSRange factorialRange = [match rangeAtIndex:11];
NSRange equalsRange = [match rangeAtIndex:12];
NSRange whitespaceRange = [match rangeAtIndex:13];
if (MPRangeExists(multiplicationSymbolRange)) {
range = multiplicationSymbolRange;
tokenType = MPMultiplicationSymbolToken;
} else if (MPRangeExists(operatorRange)) {
range = operatorRange;
tokenType = MPOperatorListToken;
} else if (MPRangeExists(numberRange)) {
range = numberRange;
tokenType = MPNumberToken;
} else if (MPRangeExists(sinRange)) {
range = sinRange;
tokenType = MPSinToken;
} else if (MPRangeExists(cosRange)) {
range = cosRange;
tokenType = MPCosToken;
} else if (MPRangeExists(tanRange)) {
range = tanRange;
tokenType = MPTanToken;
} else if (MPRangeExists(asinRange)) {
range = asinRange;
tokenType = MPASinToken;
} else if (MPRangeExists(acosRange)) {
range = acosRange;
tokenType = MPACosToken;
} else if (MPRangeExists(atanRange)) {
range = atanRange;
tokenType = MPATanToken;
} else if (MPRangeExists(variableRange)) {
range = variableRange;
tokenType = MPVariableToken;
} else if (MPRangeExists(factorialRange)) {
range = factorialRange;
tokenType = MPFactorialToken;
} else if (MPRangeExists(equalsRange)) {
range = equalsRange;
tokenType = MPEqualsToken;
} else if (MPRangeExists(whitespaceRange)) {
range = whitespaceRange;
tokenType = MPWhitespaceToken;
} else {
// Should not get here
range = NSMakeRange(lexLocation, 1);
tokenType = MPUnidentifiedToken;
}
}
lexLocation = NSMaxRange(range);
NSString *tokenStringValue = [element substringWithRange:range];
range.location += symbolIndex;
[tokens addObject:[[MPToken alloc] initWithTokenType:tokenType
range:range
stringValue:tokenStringValue]];
}
return tokens;
}
@end