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-09-28 23:50:18 +02:00

116 lines
4.5 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 "MPToken.h"
#import "MPFunction+MPToken.h"
#import "NSRegularExpression+MPParsingAdditions.h"
#define MPRangeExists(range) (range.location != NSNotFound)
@implementation MPExpressionTokenizer
- (NSArray *)tokenizeExpression:(MPExpression *)expression
{
NSMutableArray *tokens = [[NSMutableArray alloc] init];
for (NSUInteger index = 0; index < expression.numberOfElements; index++) {
id <MPExpressionElement> element = [expression elementAtIndex:index];
if ([element isFunction]) {
[tokens addObject:element];
} else {
[tokens addObjectsFromArray:[self tokenizeElement:(NSString *)element]];
}
}
return tokens;
}
- (NSArray *)tokenizeElement:(NSString *)element
{
NSUInteger lexLocation = 0;
NSString *decimalSeparator = [NSRegularExpression escapedPatternForString:[[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator]];
NSString *regexStringFormat = @"\\A(?:"
@"(\\*)|"
@"([+-](?:\\s*[+-])*)|"
@"((?:\\d+(?:%@\\d+)?)|(?:\\s%@\\d+))|"
@"(sin)|"
@"(cos)|"
@"(tan)|"
@"([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 variableRange = [match rangeAtIndex:7];
NSRange equalsRange = [match rangeAtIndex:8];
NSRange whitespaceRange = [match rangeAtIndex:9];
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(variableRange)) {
range = variableRange;
tokenType = MPVariableToken;
} 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);
[tokens addObject:[[MPToken alloc] initWithTokenType:tokenType
range:range
inString:element]];
}
return tokens;
}
@end