Archived
1

Improved Evaluation

This commit is contained in:
Kim Wittenburg
2014-09-28 23:50:18 +02:00
parent 43b6f78afb
commit d67a1949e9
19 changed files with 841 additions and 89 deletions

View File

@@ -9,105 +9,236 @@
#import "MPExpressionEvaluator.h"
#import "MPExpression.h"
#import "MPFunction.h"
#import "MPParsedFactor.h"
#import "MPFunction+MPParsedFactor.h"
#import "MPMathRules.h"
#import "MPToken.h"
#import "MPFunction+MPToken.h"
#import "MPTokenStream.h"
#import "MPEvaluationContext.h"
@interface MPExpressionEvaluator ()
@property (readwrite, nonatomic, strong) NSString *definedVariable;
@property (readwrite, nonatomic, copy) NSString *definedVariable;
@property (nonatomic, strong) NSArray *tokens;
- (void)setError:(MPParseError *)error;
@end
@implementation MPExpressionEvaluator {
MPElementParser *parser;
MPParseError *__autoreleasing *_error;
MPTokenStream *tokenStream;
}
- (id)initWithExpression:(MPExpression *)expression
{
self = [super init];
if (self) {
_expression = expression;
parser = [[MPElementParser alloc] init];
}
return self;
}
#pragma mark Evaluating Expressions
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error
@synthesize lexer = _lexer;
- (void)setLexer:(MPExpressionTokenizer *)lexer
{
return [self evaluateVariableDefinition:NO error:error];
_lexer = lexer;
self.tokens = nil;
}
- (NSDecimalNumber *)evaluateVariableDefinition:(BOOL)flag error:(MPParseError *__autoreleasing *)error
- (MPExpressionTokenizer *)lexer
{
// Empty Expression
if (self.expression.numberOfElements == 0) {
*error = MPParseError(NSMakeRange(0, 0), @"Expected Expression");
if (!_lexer) {
_lexer = [[MPExpressionTokenizer alloc] init];
}
return _lexer;
}
- (NSArray *)tokens
{
if (!_tokens) {
_tokens = [self.lexer tokenizeExpression:self.expression];
}
return _tokens;
}
- (void)expressionDidChangeInRange:(NSRange)range
replacementLength:(NSUInteger)replacementLength
{
self.tokens = nil;
}
#pragma mark Evaluating Expressions
- (void)setError:(MPParseError *)error
{
if (_error) {
error.pathToExpression = self.expression.indexPath;
*_error = error;
}
}
- (MPTerm *)parseExpectingVariable:(BOOL)flag
error:(MPParseError *__autoreleasing *)error
{
_error = error;
tokenStream = [[MPTokenStream alloc] initWithTokens:self.tokens];
if (!tokenStream.hasMoreTokens) {
self.error = MPParseError(NSMakeRange(0, 0), @"Empty Expression");
return nil;
}
NSMutableArray *products = [[NSMutableArray alloc] init];
MPParsedProduct *currentProduct = nil;
for (NSUInteger elementIndex = 0; elementIndex < self.expression.numberOfElements; elementIndex++) {
// Variable Definition
if (flag) {
MPToken *variableToken = [tokenStream nextToken];
MPToken *equalsToken = [tokenStream nextTokenOfType:MPEqualsToken];
id<MPExpressionElement> element = [self.expression elementAtIndex:elementIndex];
if ([element isString]) {
id<MPParsedFactor> nextFactor = nil;
if (elementIndex < self.expression.numberOfElements - 1) {
MPFunction *nextFunction = (MPFunction *)[self.expression elementAtIndex:elementIndex+1];
nextFactor = nextFunction;
}
NSArray *newProducts;
if (elementIndex == 0 && flag) {
NSString *definedVariable;
newProducts = [parser parseElement:(NSString *)element
previousProduct:currentProduct
nextFactor:nextFactor
definesVariable:YES
definedVariable:&definedVariable
error:error];
self.definedVariable = definedVariable;
} else {
newProducts = [parser parseElement:(NSString *)element
previousProduct:currentProduct
nextFactor:nextFactor
error:error];
}
if (!newProducts) {
return nil;
}
for (NSUInteger productIndex = 0; productIndex < newProducts.count-1; productIndex++) {
[products addObject:newProducts[productIndex]];
}
currentProduct = newProducts.lastObject;
elementIndex++;
} else {
if (!currentProduct) {
currentProduct = [[MPParsedProduct alloc] init];
} else if ([MPMathRules sharedRules].allowsImplicitMultiplication) {
[currentProduct addFactor:(MPFunction *)element];
} else {
*error = MPParseError(NSMakeRange(((MPFunction *)element).range.location, 0), @"Implicit Multiplication not allowed");
return nil;
}
}
}
[products addObject:currentProduct];
NSDecimalNumber *value = [NSDecimalNumber zero];
for (MPParsedProduct *product in products) {
NSDecimalNumber *productValue = [product evaluateWithError:error];
if (!productValue) {
if (variableToken.tokenType != MPVariableToken) {
self.error = MPParseError(variableToken.range, @"Expected Variable Definition.");
return nil;
}
if (equalsToken.tokenType != MPEqualsToken) {
self.error = MPParseError(equalsToken.range, @"Expected \"=\".");
return nil;
}
self.definedVariable = variableToken.stringValue;
}
BOOL isAtBeginning = YES;
NSMutableArray *summands = [[NSMutableArray alloc] init];
NSMutableArray *currentSummand = [[NSMutableArray alloc] init];
while (tokenStream.hasMoreTokens) {
MPToken *multiplicationToken = [tokenStream nextTokenOfType:MPMultiplicationSymbolToken];
MPToken *operatorToken = [tokenStream nextTokenOfType:MPOperatorListToken];
NSRange valueRange;
MPTerm *value = [self nextValue:&valueRange];
if (multiplicationToken) {
if (isAtBeginning) {
self.error = MPParseError(multiplicationToken.range, @"Unexpected Symbol. Expected Number.");
return nil;
}
if (operatorToken) {
if (operatorToken.numberOfOperators > [[MPMathRules sharedRules] maximumOperatorChainLengthInMultiplication]) {
self.error = MPParseError(operatorToken.range, @"Too many operators in multiplication");
return nil;
}
[currentSummand addObject:[[MPTerm alloc] initWithNumber:operatorToken.operatorValue]];
}
if (value) {
[currentSummand addObject:value];
} else {
return nil;
}
} else {
if (operatorToken) {
if (operatorToken.numberOfOperators > [[MPMathRules sharedRules] maximumOperatorChainLength]) {
self.error = MPParseError(operatorToken.range, @"Too many operators.");
return nil;
}
[summands addObject:[[MPTerm alloc] initWithFactors:currentSummand.copy]];
currentSummand = [[NSMutableArray alloc] init];
[currentSummand addObject:[[MPTerm alloc] initWithNumber:operatorToken.operatorValue]];
if (value) {
[currentSummand addObject:value];
} else {
return nil;
}
} else if (!value) {
return nil;
} else if (isAtBeginning || [[MPMathRules sharedRules] allowsImplicitMultiplication]) {
[currentSummand addObject:value];
} else {
self.error = MPParseError(NSMakeRange(valueRange.location, 0), @"Implicit Multiplication not allowed here");
return nil;
}
}
isAtBeginning = NO;
}
[summands addObject:[[MPTerm alloc] initWithFactors:currentSummand.copy]];
return [[MPTerm alloc] initWithSummands:summands.copy];
}
- (MPTerm *)nextValue:(NSRangePointer)range
{
MPToken *token = [tokenStream nextToken];
if (range) {
*range = token.range;
}
switch (token.tokenType) {
case MPNumberToken:
{
return [[MPTerm alloc] initWithNumber:token.number];
}
case MPVariableToken:
{
if(![[MPEvaluationContext sharedContext] isVariableDefined:token.variable]) {
self.error = MPParseError(token.range, @"Undefined Variable");
return nil;
}
return [[MPTerm alloc] initWithVariable:token.variable];
}
case MPGenericFunctionToken:
{
return [((MPFunction *)token) parseWithError:_error];
}
case MPSinToken:
{
NSRange sinTermRange;
MPTerm *sinTerm = [self nextValue:&sinTermRange];
if (!sinTerm) {
if (range) {
*range = NSUnionRange(token.range, sinTermRange);
}
return nil;
}
return [[MPTerm alloc] initWithSinOfTerm:sinTerm];
}
case MPCosToken:
{
NSRange cosTermRange;
MPTerm *cosTerm = [self nextValue:&cosTermRange];
if (!cosTerm) {
if (range) {
*range = NSUnionRange(token.range, cosTermRange);
}
return nil;
}
return [[MPTerm alloc] initWithSinOfTerm:cosTerm];
}
case MPTanToken:
{
NSRange tanTermRange;
MPTerm *tanTerm = [self nextValue:&tanTermRange];
if (!tanTerm) {
if (range) {
*range = NSUnionRange(token.range, tanTermRange);
}
return nil;
}
return [[MPTerm alloc] initWithTanOfTerm:tanTerm];
}
case MPEOFToken:
{
self.error = MPParseError(token.range, @"Unexpected End. Expected Number.");
return nil;
}
default:
{
self.error = MPParseError(token.range, @"Unexpected Symbol. Expected Number.");
return nil;
}
value = [value decimalNumberByAdding:productValue];
}
return value;
}
@end