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/MPElementParser.m
2014-09-07 16:45:31 +02:00

186 lines
6.1 KiB
Objective-C

//
// MPElementParser.m
// MathPad
//
// Created by Kim Wittenburg on 06.09.14.
// Copyright (c) 2014 Kim Wittenburg. All rights reserved.
//
#import "MPElementParser.h"
@implementation MPElementParser {
NSScanner *scanner;
}
- (MPParsedElement *)parseElement:(NSString *)string error:(MPParseError *__autoreleasing *)error
{
// Setup the Scanner
scanner = [[NSScanner alloc] initWithString:string];
scanner.charactersToBeSkipped = [NSCharacterSet whitespaceAndNewlineCharacterSet];
scanner.caseSensitive = YES;
MPParsedElement *parsedElement = [[MPParsedElement alloc] init];
// Scan the defined variable
NSString *firstCharacters = nil;
BOOL hasLettersInFront = [scanner scanCharactersFromSet:[NSCharacterSet letterCharacterSet]
intoString:&firstCharacters];
BOOL foundEquals = [scanner scanString:@"="
intoString:NULL];
if (hasLettersInFront && firstCharacters.length == 1 && foundEquals) {
// Found variable definition
parsedElement.definedVariable = firstCharacters;
parsedElement.afterVariableDefinitionIndex = scanner.scanLocation;
} else {
// No variable definition found, reset the scanner
parsedElement.definedVariable = nil;
scanner.scanLocation = 0;
}
// Scan the Prefix
BOOL startsWithAsterisk = [scanner scanString:@"*"
intoString:NULL];
BOOL productClosed;
NSDecimalNumber *prefix = [self scanClosedProduct:&productClosed
error:NULL];
// Simple Factor
if (scanner.isAtEnd) {
parsedElement.isFactor = YES;
parsedElement.value = prefix == nil ? [NSDecimalNumber one] : prefix;
parsedElement.prefixOperatorExplicit = startsWithAsterisk;
parsedElement.suffixOperatorExplicit = !productClosed;
parsedElement.suffixIndex = scanner.scanLocation;
return parsedElement;
} else if (!productClosed) {
if (error) {
*error = MPParseError(scanner.scanLocation, @"Missing Number");
}
return nil;
}
parsedElement.prefixOperatorExplicit = startsWithAsterisk;
parsedElement.prefixValueExplicit = YES;
parsedElement.prefixMultiplicator = prefix;
parsedElement.suffixValueExplicit = YES;
// Scan Summands
NSDecimalNumber *value = [NSDecimalNumber zero];
NSDecimalNumber *currentSummand;
while (!scanner.isAtEnd) {
// Add every summand but the last one
if (currentSummand != nil) {
value = [value decimalNumberByAdding:currentSummand];
}
// Find the operator (+ or -)
NSString *operator;
BOOL found = [scanner scanString:@"+"
intoString:&operator];
if (!found) {
found = [scanner scanString:@"-"
intoString:&operator];
}
if (!found && !scanner.isAtEnd) {
// Two numbers separated by just a space
if (error) {
*error = MPParseError(scanner.scanLocation, @"Missing Operator");
}
return nil;
} else if (!found) {
// Reached end of string
break;
}
currentSummand = [self scanClosedProduct:&productClosed
error:error];
// No number was found
if (currentSummand == nil) {
// The string ends wit + or -
if (scanner.isAtEnd) {
productClosed = NO;
parsedElement.suffixValueExplicit = NO;
NSInteger suffix = [operator isEqualToString:@"+"] ? 1 : -1;
currentSummand = [[NSDecimalNumber alloc] initWithInteger:suffix];
if (error) {
*error = nil;
}
break;
// Something else instead of a number
} else {
if (error) {
*error = MPParseError(scanner.scanLocation, @"Expected Number");
}
return nil;
}
}
// Process the current summand
if ([operator isEqualToString:@"-"]) {
currentSummand = [currentSummand decimalNumberByMultiplyingBy:[[NSDecimalNumber alloc] initWithInteger:-1]];
}
// The summand ends with a *
if (!productClosed) {
// The string ends with a *
if (scanner.isAtEnd) {
parsedElement.suffixValueExplicit = YES;
break;
// After a * followed something else than a number
} else {
if (error) {
*error = MPParseError(scanner.scanLocation, @"Unexpected Symbol");
}
return nil;
}
}
}
parsedElement.value = value;
parsedElement.suffixOperatorExplicit = !productClosed;
parsedElement.suffixMultiplicator = currentSummand;
parsedElement.suffixIndex = scanner.scanLocation;
return parsedElement;
}
- (NSDecimalNumber *)scanClosedProduct:(BOOL *)closed error:(MPParseError **)error
{
NSDecimal decimal;
BOOL found = [scanner scanDecimal:&decimal];
if (!found) {
if (error != NULL) {
*error = MPParseError(scanner.scanLocation, @"Unexpected Symbol");
}
return nil;
}
NSDecimalNumber *product = [NSDecimalNumber decimalNumberWithDecimal:decimal];
while (true) {
found = [scanner scanString:@"*"
intoString:NULL];
if (found) {
found = [scanner scanDecimal:&decimal];
if (found) {
product = [product decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithDecimal:decimal]];
} else {
if (closed != NULL) {
*closed = NO;
}
return product;
}
} else {
break;
}
}
if (closed != NULL) {
*closed = YES;
}
return product;
}
@end