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/MPExpressionEvaluator.m
2014-09-28 23:50:18 +02:00

245 lines
7.3 KiB
Objective-C

//
// MPExpressionEvaluator.m
// MathPad
//
// Created by Kim Wittenburg on 31.08.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPExpressionEvaluator.h"
#import "MPExpression.h"
#import "MPFunction.h"
#import "MPMathRules.h"
#import "MPToken.h"
#import "MPFunction+MPToken.h"
#import "MPTokenStream.h"
#import "MPEvaluationContext.h"
@interface MPExpressionEvaluator ()
@property (readwrite, nonatomic, copy) NSString *definedVariable;
@property (nonatomic, strong) NSArray *tokens;
- (void)setError:(MPParseError *)error;
@end
@implementation MPExpressionEvaluator {
MPParseError *__autoreleasing *_error;
MPTokenStream *tokenStream;
}
- (id)initWithExpression:(MPExpression *)expression
{
self = [super init];
if (self) {
_expression = expression;
}
return self;
}
@synthesize lexer = _lexer;
- (void)setLexer:(MPExpressionTokenizer *)lexer
{
_lexer = lexer;
self.tokens = nil;
}
- (MPExpressionTokenizer *)lexer
{
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;
}
// Variable Definition
if (flag) {
MPToken *variableToken = [tokenStream nextToken];
MPToken *equalsToken = [tokenStream nextTokenOfType:MPEqualsToken];
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;
}
}
}
@end